├── .gitignore ├── pom.xml ├── readme.md └── src ├── main ├── java │ └── com │ │ └── github │ │ └── middleware │ │ └── fsm │ │ ├── builder │ │ ├── StateMachine.java │ │ ├── StateMachines.java │ │ ├── chain │ │ │ ├── From.java │ │ │ ├── LocalTransitionBuilder.java │ │ │ ├── On.java │ │ │ ├── To.java │ │ │ ├── TransitionActivity.java │ │ │ ├── TransitionCriteria.java │ │ │ ├── TransitionDefine.java │ │ │ ├── When.java │ │ │ ├── dto │ │ │ │ └── TransitionResult.java │ │ │ └── support │ │ │ │ ├── LocalTransitionBuilderImpl.java │ │ │ │ └── TransitionImpl.java │ │ ├── event │ │ │ ├── ActionEvent.java │ │ │ ├── AfterExecActionEvent.java │ │ │ ├── AfterExecActionListener.java │ │ │ ├── AsyncEventListener.java │ │ │ ├── BaseEvent.java │ │ │ ├── BaseListener.java │ │ │ ├── BeforeExecActionEvent.java │ │ │ ├── BeforeExecActionListener.java │ │ │ ├── EventType.java │ │ │ ├── ExecActionExceptionEvent.java │ │ │ ├── ExecActionExceptionListener.java │ │ │ ├── ListenerMapping.java │ │ │ ├── StateMachineEvent.java │ │ │ ├── TransitionBeginEvent.java │ │ │ ├── TransitionBeginListener.java │ │ │ ├── TransitionCompleteEvent.java │ │ │ ├── TransitionCompleteListener.java │ │ │ ├── TransitionDeclinedEvent.java │ │ │ ├── TransitionDeclinedListener.java │ │ │ ├── TransitionEndEvent.java │ │ │ ├── TransitionEndListener.java │ │ │ ├── TransitionEvent.java │ │ │ ├── TransitionExceptionEvent.java │ │ │ ├── TransitionExceptionListener.java │ │ │ ├── annotation │ │ │ │ ├── AsyncExec.java │ │ │ │ ├── ListenerOrder.java │ │ │ │ ├── OnActionException.java │ │ │ │ ├── OnAfterAction.java │ │ │ │ ├── OnBeforeAction.java │ │ │ │ ├── OnTransitionBegin.java │ │ │ │ ├── OnTransitionComplete.java │ │ │ │ ├── OnTransitionDecline.java │ │ │ │ ├── OnTransitionEnd.java │ │ │ │ └── OnTransitionException.java │ │ │ ├── dto │ │ │ │ ├── ListenerMappingContext.java │ │ │ │ ├── ListenerMappingContextItem.java │ │ │ │ └── ListenerMethod.java │ │ │ └── support │ │ │ │ ├── AbstractExecActionEvent.java │ │ │ │ ├── AbstractStateMachineEvent.java │ │ │ │ ├── AbstractTransitionEvent.java │ │ │ │ ├── AfterExecActionEventImpl.java │ │ │ │ ├── BeforeExecActionEventImpl.java │ │ │ │ ├── ExecActionExceptionEventImpl.java │ │ │ │ ├── TransitionBeginEventImpl.java │ │ │ │ ├── TransitionCompleteEventImpl.java │ │ │ │ ├── TransitionDeclinedEventImpl.java │ │ │ │ ├── TransitionEndEventImpl.java │ │ │ │ └── TransitionExceptionEventImpl.java │ │ ├── exec │ │ │ ├── Action.java │ │ │ ├── ActionExecService.java │ │ │ ├── EntryExitBuilder.java │ │ │ ├── annotation │ │ │ │ └── ExecWhen.java │ │ │ ├── dto │ │ │ │ ├── ExecServiceContext.java │ │ │ │ ├── RegularTransition.java │ │ │ │ └── RuleExecContext.java │ │ │ └── support │ │ │ │ ├── AbstractAction.java │ │ │ │ ├── AbstractExecService.java │ │ │ │ ├── ActionExecServiceImpl.java │ │ │ │ ├── ActionImpl.java │ │ │ │ ├── ActionWrapper.java │ │ │ │ ├── EntryExitBuilderImpl.java │ │ │ │ ├── MethodCallImpl.java │ │ │ │ └── MethodCallProxyImpl.java │ │ ├── machine │ │ │ ├── StateMachineBuilder.java │ │ │ ├── annotation │ │ │ │ └── HoldPayload.java │ │ │ ├── dto │ │ │ │ ├── RequestPayload.java │ │ │ │ ├── StateMachineContext.java │ │ │ │ └── StateMachineData.java │ │ │ ├── factroy │ │ │ │ └── StateMachineBuilderFactory.java │ │ │ └── support │ │ │ │ ├── AbstractStateMachine.java │ │ │ │ ├── AbstractSubject.java │ │ │ │ ├── StateMachineBuilderImpl.java │ │ │ │ └── visit │ │ │ │ ├── AbstractStateMachineProxy.java │ │ │ │ ├── DefaultStateMachineBuilder.java │ │ │ │ ├── StateMachineBuilderProxy.java │ │ │ │ └── StateMachineProxy.java │ │ ├── plugin │ │ │ ├── PluginBuilder.java │ │ │ ├── PluginLiftcycle.java │ │ │ ├── PluginProvider.java │ │ │ ├── log │ │ │ │ ├── LogExec.java │ │ │ │ └── support │ │ │ │ │ └── FsmListenerLogger.java │ │ │ └── support │ │ │ │ ├── AbstractPluginProvider.java │ │ │ │ └── PluginBuilderImpl.java │ │ ├── selector │ │ │ ├── QueueStrategy.java │ │ │ ├── ReentrantLockStrategy.java │ │ │ ├── SingleStrategy.java │ │ │ └── StateMachineStrategy.java │ │ └── state │ │ │ ├── ImmutableLinkedState.java │ │ │ ├── StateActivity.java │ │ │ ├── StateCriteria.java │ │ │ ├── StateDefine.java │ │ │ ├── StateLiftcycle.java │ │ │ ├── dto │ │ │ └── StateContext.java │ │ │ └── support │ │ │ ├── AbstractState.java │ │ │ ├── ChoiceStateDefine.java │ │ │ ├── SimpleStateDefine.java │ │ │ ├── StateImpl.java │ │ │ └── visit │ │ │ └── ProxyStateDefine.java │ │ ├── config │ │ ├── annotation │ │ │ ├── State.java │ │ │ ├── StateMachineParameters.java │ │ │ ├── States.java │ │ │ ├── Transition.java │ │ │ └── Transitions.java │ │ ├── application │ │ │ ├── AbstractConfig.java │ │ │ └── StateMachineConfig.java │ │ └── loader │ │ │ ├── AnnotationResovler.java │ │ │ └── support │ │ │ ├── AnnotationResovlerImpl.java │ │ │ ├── AntrlStateLoader.java │ │ │ └── XmlStateLoader.java │ │ ├── core │ │ ├── Singletonable.java │ │ ├── Version.java │ │ ├── convert │ │ │ ├── Converter.java │ │ │ ├── ConverterProvider.java │ │ │ ├── PayloadParse.java │ │ │ └── support │ │ │ │ ├── ConverterImpl.java │ │ │ │ └── ConverterProviderImpl.java │ │ ├── el │ │ │ ├── Dsl.java │ │ │ ├── MvelScriptManager.java │ │ │ └── support │ │ │ │ └── MvelScriptManagerImpl.java │ │ ├── extension │ │ │ └── SPI.java │ │ ├── factory │ │ │ ├── DependProvider.java │ │ │ ├── SingletonProviderFactory.java │ │ │ └── ThreadExecutorService.java │ │ ├── types │ │ │ ├── ProcessingQueue.java │ │ │ └── TypeReference.java │ │ └── utils │ │ │ ├── IDProvider.java │ │ │ ├── JsonUtil.java │ │ │ ├── Precondition.java │ │ │ ├── ReflectUtil.java │ │ │ └── StringUtil.java │ │ ├── exception │ │ ├── ApiObsoleteException.java │ │ ├── ErrorCode.java │ │ ├── EventAlreadyExistsException.java │ │ ├── EventNotDefinedException.java │ │ ├── IllegalAnnotationException.java │ │ ├── IllegalPreCheckerException.java │ │ ├── NotPayloadException.java │ │ ├── NotSuchEventException.java │ │ ├── NotSuchStateException.java │ │ ├── NotSupportedException.java │ │ ├── SateAlreadyExistsException.java │ │ ├── StateMachineException.java │ │ └── StateNotDefinedException.java │ │ ├── filter │ │ ├── annotation │ │ │ └── PostConstruct.java │ │ ├── validator │ │ │ ├── PreChecker.java │ │ │ └── support │ │ │ │ ├── AbstractPreChecker.java │ │ │ │ ├── MvelCheckerImpl.java │ │ │ │ └── PreCheckers.java │ │ └── wrapper │ │ │ ├── ComposPostProcessor.java │ │ │ ├── PostProcessor.java │ │ │ ├── PostProcessorProvider.java │ │ │ └── support │ │ │ ├── ComposPostProcessorImpl.java │ │ │ └── PostConstructPostProcessorImpl.java │ │ └── spring │ │ ├── StatemachineBuilderSupport.java │ │ ├── StatemachineFactoryBean.java │ │ ├── StatemachineScannerConfigurer.java │ │ └── annotation │ │ └── StatemachineService.java └── resources │ ├── images │ └── thread.jpg │ └── logback.xml └── test ├── java └── com │ └── github │ └── middleware │ └── fsm │ ├── builder │ ├── AnnotationResovler_test.java │ ├── Performance_Test.java │ └── dto │ │ └── Order.java │ ├── client │ ├── LinkLamda_test.java │ ├── QuickStartV2_test.java │ ├── QuickStart_test.java │ ├── constants │ │ ├── OrderEvent.java │ │ └── OrderState.java │ └── v2 │ │ ├── OrderStateMachineImplV2.java │ │ └── OrderStateMachineV2.java │ ├── core │ ├── Converter_Test.java │ ├── DependProvider_test.java │ ├── MvelScriptManager_test.java │ ├── ReflectUtil_test.java │ ├── Swith.java │ └── support │ │ └── SwithImpl.java │ └── filter │ ├── MvelChecker_test.java │ └── PostProcessor_test.java └── resources └── spring-statemachine.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | 49 | 50 | 51 | #my 52 | /target/ 53 | /.classpath 54 | /.settings 55 | /.project 56 | /.idea 57 | *.iml 58 | /.springBeans -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.github.middleware 7 | j-statemachine 8 | 1.5.1.RELEASE 9 | 10 | jar 11 | 12 | 3.2.12.RELEASE 13 | 14 | 15 | 16 | 17 | com.google.guava 18 | guava 19 | 19.0 20 | 21 | 22 | org.apache.commons 23 | commons-lang3 24 | 3.4 25 | 26 | 27 | org.mvel 28 | mvel2 29 | 2.2.4.Final 30 | 31 | 32 | 33 | org.slf4j 34 | slf4j-api 35 | 1.7.21 36 | 37 | 38 | ch.qos.logback 39 | logback-core 40 | 1.1.3 41 | 42 | 43 | ch.qos.logback 44 | logback-classic 45 | 1.1.3 46 | 47 | 48 | com.alibaba 49 | fastjson 50 | 1.1.41 51 | 52 | 53 | 54 | org.springframework 55 | spring-core 56 | ${spring.version} 57 | 58 | 59 | org.springframework 60 | spring-beans 61 | ${spring.version} 62 | 63 | 64 | org.springframework 65 | spring-context 66 | ${spring.version} 67 | 68 | 69 | org.springframework 70 | spring-test 71 | ${spring.version} 72 | 73 | 74 | 75 | junit 76 | junit 77 | 4.12 78 | test 79 | 80 | 81 | org.hamcrest 82 | hamcrest-all 83 | 1.3 84 | test 85 | 86 | 87 | 88 | 89 | snapshots 90 | http://192.168.1.180:8091/nexus/content/repositories/snapshots 91 | 92 | 93 | releases 94 | http://192.168.1.180:8091/nexus/content/repositories/releases 95 | 96 | 97 | 98 | 99 | 100 | maven-compiler-plugin 101 | 102 | 1.8 103 | 1.8 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/StateMachine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder; 2 | 3 | import com.github.middleware.fsm.builder.event.*; 4 | import com.github.middleware.fsm.builder.state.StateDefine; 5 | import com.github.middleware.fsm.config.application.StateMachineConfig; 6 | import com.github.middleware.fsm.exception.StateMachineException; 7 | 8 | import java.util.Set; 9 | 10 | /** 11 | * 有限状态机定义 12 | * 13 | * @param 状态机 14 | * @param 状态源:String/Enum 15 | * @param 触发事件:String/Enum 16 | * @param 携带报文 17 | */ 18 | public interface StateMachine, S, E, C> { 19 | /** 20 | * 触发事件 21 | * 22 | * @param event 23 | */ 24 | void handleEvent(E event); 25 | 26 | void handleEvent(E event, C context); 27 | void handleEvent(S initialStateName,E event, C context); 28 | /** 29 | * 测试状态扭转,并返回结果 30 | * 31 | * @param event 32 | * @param context 33 | * @return 34 | */ 35 | //S test(E event, C context); 36 | 37 | /** 38 | * 测试事件是否有效 39 | * 40 | * @param event 41 | * @return 42 | */ 43 | boolean canAccept(E event); 44 | 45 | /** 46 | * 状态机标示 47 | * 48 | * @return 49 | */ 50 | String identifier(); 51 | 52 | void identifier(String id); 53 | 54 | /** 55 | * 状态机的实例 56 | * 57 | * @return 58 | */ 59 | StateMachine getThis(); 60 | 61 | /** 62 | * 获取所有状态 63 | * 64 | * @return 65 | */ 66 | Set getStates(); 67 | 68 | /** 69 | * 获取初始化状态 70 | * 71 | * @return 72 | */ 73 | S getInitialState(); 74 | 75 | StateDefine getInitialRawState(); 76 | 77 | /** 78 | * 获取当前状态 79 | * 80 | * @return 81 | */ 82 | S getCurrentState(); 83 | 84 | StateDefine getCurrentRawState(); 85 | 86 | /** 87 | * 获取最终状态 88 | * 89 | * @return 90 | */ 91 | S getLastState(); 92 | 93 | StateDefine getLastRawState(); 94 | 95 | /** 96 | * 获取执行异常信息 97 | * 98 | * @return 99 | */ 100 | StateMachineException getLastException(); 101 | 102 | StateMachineConfig getConfig(); 103 | /** 104 | * transition action 105 | * 106 | * @param fromState 107 | * @param toState 108 | * @param event 109 | * @param context 110 | */ 111 | void beforeActionInvoked(S fromState, S toState, E event, C context); 112 | 113 | void afterActionInvoked(S fromState, S toState, E event, C context); 114 | 115 | /** 116 | * 添加各种listener 117 | * 118 | * @param listener 119 | */ 120 | void addTransitionBeginListener(TransitionBeginListener listener); 121 | 122 | void removeTransitionBeginListener(TransitionBeginListener listener); 123 | 124 | void addTransitionCompleteListener(TransitionCompleteListener listener); 125 | 126 | void removeTransitionCompleteListener(TransitionCompleteListener listener); 127 | 128 | void addTransitionExceptionListener(TransitionExceptionListener listener); 129 | 130 | void removeTransitionExceptionListener(TransitionExceptionListener listener); 131 | 132 | void addTransitionDeclinedListener(TransitionDeclinedListener listener); 133 | 134 | void removeTransitionDeclinedListener(TransitionDeclinedListener listener); 135 | 136 | void addTransitionEndListener(TransitionEndListener listener); 137 | 138 | void removeTransitionEndListener(TransitionEndListener listener); 139 | 140 | void addExecActionListener(BeforeExecActionListener listener); 141 | 142 | void removeExecActionListener(BeforeExecActionListener listener); 143 | 144 | /** 145 | * 启动各种插件支持 146 | */ 147 | void pluginsStart(); 148 | /** 149 | * 触发事件执行流 150 | * 151 | * @param fromStateId 152 | * @param event 153 | * @param context 154 | */ 155 | // void beforeTransitionBegin(S fromStateId, E event, C context); 156 | // void afterTransitionDeclined(S fromStateId, E event, C context); 157 | // void afterTransitionCompleted(S fromStateId, Object currentState, E event, C context); 158 | // void afterTransitionCausedException(S fromStateId, S toStateId, E event, C context); 159 | // void afterTransitionEnd(S fromStateId, Object currentState, E event, C context); 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/From.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.el.Dsl; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/6 10 | */ 11 | public interface From, S, E, C> extends Dsl { 12 | To to(S state); 13 | 14 | To toEnd(S state); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/LocalTransitionBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/7 9 | */ 10 | public interface LocalTransitionBuilder, S, E, C> { 11 | From from(S state); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/On.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.filter.validator.PreChecker; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/6 10 | */ 11 | public interface On, S, E, C> extends When { 12 | When when(PreChecker checker); 13 | When whenMvel(String expression); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/To.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.el.Dsl; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/6 10 | */ 11 | public interface To, S, E, C> extends Dsl { 12 | On on(E event); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/TransitionActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.state.StateDefine; 4 | import com.github.middleware.fsm.builder.state.dto.StateContext; 5 | import com.github.middleware.fsm.builder.StateMachine; 6 | 7 | /** 8 | * 扭转交互 9 | * Created by YT on 2017/3/8. 10 | */ 11 | public interface TransitionActivity, S, E, C> { 12 | /** 13 | * 触发扭转链检查 14 | * 15 | * @param stateContext 16 | */ 17 | void fireInternal(StateContext stateContext); 18 | 19 | /** 20 | * 执行 transition action 21 | * 22 | * @param stateContext 23 | * @return 24 | */ 25 | StateDefine pass(StateContext stateContext); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/TransitionCriteria.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.el.Dsl; 5 | import com.github.middleware.fsm.builder.exec.Action; 6 | import com.github.middleware.fsm.filter.validator.PreChecker; 7 | 8 | /** 9 | * 链式语法支持 10 | * 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/2/28 14 | */ 15 | @Deprecated 16 | public interface TransitionCriteria, S, E, C> extends Dsl { 17 | @Deprecated 18 | TransitionDefine to(S stateName); 19 | @Deprecated 20 | TransitionDefine toChoice(S choiceName); 21 | @Deprecated 22 | TransitionDefine onEvent(E event); 23 | @Deprecated 24 | TransitionDefine preCheckerElse(); 25 | @Deprecated 26 | TransitionDefine preChecker(PreChecker preChecker); 27 | @Deprecated 28 | TransitionDefine withAction(Action action); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/TransitionDefine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.state.StateDefine; 4 | import com.github.middleware.fsm.builder.StateMachine; 5 | import com.github.middleware.fsm.filter.validator.PreChecker; 6 | import com.github.middleware.fsm.builder.exec.Action; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 状态扭转链 12 | * 13 | * @author alex.chen 14 | * @version 1.0.0 15 | * @date 2017/2/27 16 | */ 17 | public interface TransitionDefine, S, E, C> extends TransitionActivity, TransitionCriteria { 18 | void setFromState(StateDefine state); 19 | void setToState(StateDefine state); 20 | void setPreChecker(PreChecker preChecker); 21 | void addAction(Action action); 22 | void setEvent(E event); 23 | 24 | E getEvent(); 25 | StateDefine getFromState(); 26 | StateDefine getToState(); 27 | PreChecker getPreChecker(); 28 | List getActionList(); 29 | boolean isEqual(S fromState, S toState, E event); 30 | boolean isEqual(S fromState, S toState, E event, Class checker); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/When.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | import com.github.middleware.fsm.core.el.Dsl; 6 | 7 | /** 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/3/6 11 | */ 12 | public interface When, S, E, C> extends Dsl { 13 | /** 14 | * 完成 15 | * 16 | * @param action 17 | */ 18 | void complete(Action action); 19 | void complete(String callMethod); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/dto/TransitionResult.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain.dto; 2 | 3 | import com.github.middleware.fsm.builder.state.StateDefine; 4 | import com.google.common.collect.Lists; 5 | import com.github.middleware.fsm.builder.StateMachine; 6 | 7 | import java.io.Serializable; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | /** 12 | * @author alex.chen 13 | * @version 1.0.0 14 | * @date 2017/3/8 15 | */ 16 | public class TransitionResult, S, E, C> implements Serializable { 17 | private boolean accepted; 18 | private StateDefine toState; 19 | private TransitionResult parent; 20 | private List> subResults; 21 | 22 | public TransitionResult(boolean accepted, StateDefine toState, TransitionResult parent) { 23 | this.accepted = accepted; 24 | this.toState = toState; 25 | this.parent = parent; 26 | } 27 | 28 | private void addSubResult(TransitionResult subResult) { 29 | if (subResults == null) 30 | subResults = Lists.newArrayList(); 31 | subResults.add(subResult); 32 | } 33 | 34 | public boolean isAccepted() { 35 | if (accepted) { 36 | return true; 37 | } else if (subResults != null) { 38 | for (TransitionResult subResult : getSubResults()) { 39 | if (subResult.isAccepted()) return true; 40 | } 41 | } 42 | return false; 43 | } 44 | 45 | public TransitionResult setAccepted(boolean accepted) { 46 | this.accepted = accepted; 47 | return this; 48 | } 49 | 50 | public StateDefine getToState() { 51 | return toState; 52 | } 53 | 54 | public TransitionResult setToState(StateDefine toState) { 55 | this.toState = toState; 56 | return this; 57 | } 58 | 59 | public List> getSubResults() { 60 | return subResults != null ? Lists.newArrayList(subResults) : 61 | Collections.>emptyList(); 62 | } 63 | 64 | public TransitionResult setParent(TransitionResult parent) { 65 | this.parent = parent; 66 | if (parent != null && parent instanceof TransitionResult) { 67 | ((TransitionResult) parent).addSubResult(this); 68 | } 69 | return this; 70 | } 71 | 72 | public TransitionResult getParentResut() { 73 | return parent; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/chain/support/LocalTransitionBuilderImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.chain.support; 2 | 3 | import com.github.middleware.fsm.builder.chain.*; 4 | import com.github.middleware.fsm.builder.state.StateDefine; 5 | import com.github.middleware.fsm.builder.StateMachine; 6 | import com.github.middleware.fsm.builder.StateMachines; 7 | import com.github.middleware.fsm.builder.exec.Action; 8 | import com.github.middleware.fsm.builder.exec.dto.RuleExecContext; 9 | import com.github.middleware.fsm.builder.chain.TransitionDefine; 10 | import com.github.middleware.fsm.filter.validator.PreChecker; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.Map; 15 | 16 | /** 17 | * @author alex.chen 18 | * @version 1.0.0 19 | * @date 2017/3/7 20 | */ 21 | public class LocalTransitionBuilderImpl, S, E, C> implements LocalTransitionBuilder, From, To, On { 22 | private static final Logger LOGGER = LoggerFactory.getLogger(LocalTransitionBuilderImpl.class); 23 | private Map> states; 24 | private RuleExecContext execContext; 25 | private StateDefine from; 26 | private StateDefine to; 27 | private TransitionDefine transition; 28 | 29 | 30 | public LocalTransitionBuilderImpl(Map> states, RuleExecContext execContext) { 31 | this.states = states; 32 | this.execContext = execContext; 33 | } 34 | 35 | @Override 36 | public From from(S state) { 37 | from = StateMachines.getState(states, state); 38 | return this; 39 | } 40 | 41 | @Override 42 | public To to(S stateId) { 43 | to = StateMachines.getState(states, stateId); 44 | return this; 45 | } 46 | 47 | @Override 48 | public To toEnd(S stateId) { 49 | to = StateMachines.getState(states, stateId); 50 | if (!to.isEndState()) { 51 | to.setEndState(true); 52 | } 53 | return this; 54 | } 55 | 56 | @Override 57 | public On on(E event) { 58 | transition = from.addTransitionOn(event); 59 | transition.setToState(to); 60 | LOGGER.debug("fsm.load add Transition On:" + from.getName() + ">" + to.getName() + ">" + event); 61 | return this; 62 | } 63 | 64 | @Override 65 | public When when(PreChecker checker) { 66 | transition.setPreChecker(checker); 67 | return this; 68 | } 69 | 70 | @Override 71 | public When whenMvel(String expression) { 72 | PreChecker checker = StateMachines.newMvelCondition(expression, execContext.getScriptManager()); 73 | transition.setPreChecker(checker); 74 | return this; 75 | } 76 | 77 | @Override 78 | public void complete(Action action) { 79 | LOGGER.debug("fsm.load add Action:" + action.getName()); 80 | transition.addAction(action); 81 | } 82 | 83 | @Override 84 | public void complete(String callMethod) { 85 | Action action = StateMachines.newMethodCallActionProxy(callMethod, execContext); 86 | transition.addAction(action); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/ActionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | 6 | /** 7 | * action事件 8 | * 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface ActionEvent, S, E, C> extends BaseEvent { 14 | Action getExecutionTarget(); 15 | 16 | S getFrom(); 17 | 18 | S getTo(); 19 | 20 | E getEvent(); 21 | 22 | C getContext(); 23 | 24 | T getStateMachine(); 25 | 26 | int[] getMOfN(); 27 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/AfterExecActionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface AfterExecActionEvent, S, E, C> extends ActionEvent { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/AfterExecActionListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface AfterExecActionListener, S, E, C> extends BaseListener { 14 | String METHOD_NAME = "afterExecute"; 15 | Method METHOD = ReflectUtil.getMethod(AfterExecActionListener.class, METHOD_NAME, new Class[]{AfterExecActionEvent.class}); 16 | 17 | void afterExecute(AfterExecActionEvent event); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/AsyncEventListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | /** 4 | * 事件(开启异步多线程) 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface AsyncEventListener { 11 | long timeout(); 12 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/BaseEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | /** 4 | * 总事件 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/6 9 | */ 10 | public interface BaseEvent { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/BaseListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | /** 4 | * Created by YT on 2017/3/16. 5 | */ 6 | public interface BaseListener { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/BeforeExecActionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface BeforeExecActionEvent, S, E, C> extends ActionEvent { 11 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/BeforeExecActionListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface BeforeExecActionListener, S, E, C> extends BaseListener{ 14 | public static final String METHOD_NAME = "beforeExecute"; 15 | public static final Method METHOD = ReflectUtil.getMethod( 16 | BeforeExecActionListener.class, METHOD_NAME, new Class[]{BeforeExecActionEvent.class}); 17 | 18 | void beforeExecute(BeforeExecActionEvent event); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/EventType.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | 4 | /** 5 | * 好像只有全局事件,先废弃吧 6 | * 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/6 10 | */ 11 | public enum EventType { 12 | Transition, 13 | Action 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/ExecActionExceptionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.exception.StateMachineException; 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface ExecActionExceptionEvent, S, E, C> extends ActionEvent { 11 | StateMachineException getException(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/ExecActionExceptionListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface ExecActionExceptionListener, S, E, C> extends BaseListener { 14 | String METHOD_NAME = "executeException"; 15 | Method METHOD = ReflectUtil.getMethod(ExecActionExceptionListener.class, METHOD_NAME, new Class[]{ExecActionExceptionEvent.class}); 16 | 17 | void executeException(ExecActionExceptionEvent event); 18 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/ListenerMapping.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.event.annotation.*; 4 | 5 | /** 6 | * Created by YT on 2017/3/16. 7 | */ 8 | public interface ListenerMapping { 9 | String LISTENER_ANNOTATION_WHEN_NAME = "when"; 10 | String LISTENER_FIELD_NAME="METHOD"; 11 | Class[][] SATE_LISTENER_MAPPING = { 12 | {OnTransitionBegin.class, TransitionBeginListener.class, TransitionBeginEvent.class}, 13 | {OnTransitionComplete.class, TransitionCompleteListener.class, TransitionCompleteEvent.class}, 14 | {OnTransitionDecline.class, TransitionDeclinedListener.class, TransitionDeclinedEvent.class}, 15 | {OnTransitionEnd.class, TransitionEndListener.class, TransitionEndEvent.class}, 16 | {OnTransitionException.class, TransitionExceptionListener.class, TransitionExceptionEvent.class} 17 | }; 18 | Class[][] ACTION_LISTENR_MAPPING = { 19 | {OnBeforeAction.class, BeforeExecActionListener.class, BeforeExecActionEvent.class}, 20 | {OnAfterAction.class, AfterExecActionListener.class, AfterExecActionEvent.class}, 21 | {OnActionException.class, ExecActionExceptionListener.class, ExecActionExceptionEvent.class}, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/StateMachineEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * 状态机事件: 7 | * TODO:赞未使用 8 | * 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface StateMachineEvent, S, E, C> extends BaseEvent { 14 | T getStateMachine(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionBeginEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface TransitionBeginEvent, S, E, C> extends TransitionEvent { 11 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionBeginListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface TransitionBeginListener, S, E, C> extends BaseListener { 14 | String METHOD_NAME = "transitionBegin"; 15 | Method METHOD = ReflectUtil.getMethod(TransitionBeginListener.class, METHOD_NAME, new Class[]{TransitionBeginEvent.class}); 16 | 17 | void transitionBegin(TransitionBeginEvent event); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionCompleteEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface TransitionCompleteEvent, S, E, C> extends TransitionEvent { 11 | S getTargetState(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionCompleteListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface TransitionCompleteListener, S, E, C> extends BaseListener{ 14 | String METHOD_NAME = "transitionComplete"; 15 | Method METHOD = ReflectUtil.getMethod(TransitionCompleteListener.class, METHOD_NAME, new Class[]{TransitionCompleteEvent.class}); 16 | 17 | void transitionComplete(TransitionCompleteEvent event); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionDeclinedEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface TransitionDeclinedEvent, S, E, C> extends TransitionEvent { 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionDeclinedListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface TransitionDeclinedListener, S, E, C> extends BaseListener { 14 | String METHOD_NAME = "transitionDeclined"; 15 | Method METHOD = ReflectUtil.getMethod(TransitionDeclinedListener.class, METHOD_NAME, new Class[]{TransitionDeclinedEvent.class}); 16 | 17 | void transitionDeclined(TransitionDeclinedEvent event); 18 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionEndEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | public interface TransitionEndEvent, S, E, C> extends TransitionEvent { 11 | S getTargetState(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionEndListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface TransitionEndListener, S, E, C> extends BaseListener{ 14 | String METHOD_NAME = "transitionEnd"; 15 | Method METHOD = ReflectUtil.getMethod(TransitionEndListener.class, METHOD_NAME, new Class[]{TransitionEndEvent.class}); 16 | 17 | void transitionEnd(TransitionEndEvent event); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * 扭转事件 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public interface TransitionEvent, S, E, C> extends StateMachineEvent { 12 | S getSourceState(); 13 | 14 | E getCause(); 15 | 16 | C getContext(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionExceptionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.exception.StateMachineException; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public interface TransitionExceptionEvent, S, E, C> extends TransitionEvent { 12 | S getTargetState(); 13 | 14 | StateMachineException getException(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/TransitionExceptionListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/8 12 | */ 13 | public interface TransitionExceptionListener, S, E, C> extends BaseListener{ 14 | String METHOD_NAME = "transitionException"; 15 | Method METHOD = ReflectUtil.getMethod(TransitionExceptionListener.class, METHOD_NAME, new Class[]{TransitionExceptionEvent.class}); 16 | 17 | void transitionException(TransitionExceptionEvent event); 18 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/AsyncExec.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/17 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ElementType.TYPE, ElementType.METHOD}) 13 | public @interface AsyncExec { 14 | long timeout() default -1; 15 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/ListenerOrder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Deprecated 11 | @Documented 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target({ElementType.TYPE, ElementType.METHOD}) 14 | public @interface ListenerOrder { 15 | int value(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnActionException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnActionException { 14 | String when() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnAfterAction.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnAfterAction { 14 | String when() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnBeforeAction.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnBeforeAction { 14 | String when() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnTransitionBegin.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnTransitionBegin { 14 | String when() default ""; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnTransitionComplete.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnTransitionComplete { 14 | String when() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnTransitionDecline.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnTransitionDecline { 14 | String when() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnTransitionEnd.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnTransitionEnd { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/annotation/OnTransitionException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/8 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OnTransitionException { 14 | String when() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/dto/ListenerMappingContext.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.dto; 2 | 3 | import com.github.middleware.fsm.builder.plugin.PluginProvider; 4 | import com.google.common.collect.Lists; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/16 13 | */ 14 | public class ListenerMappingContext implements Serializable { 15 | private PluginProvider pluginProvider; 16 | private List mappingContextItems; 17 | 18 | public ListenerMappingContext() { 19 | this(null); 20 | } 21 | 22 | public ListenerMappingContext(PluginProvider pluginProvider) { 23 | this.pluginProvider = pluginProvider; 24 | mappingContextItems = Lists.newArrayList(); 25 | } 26 | 27 | public PluginProvider getPluginProvider() { 28 | return pluginProvider; 29 | } 30 | 31 | public void setPluginProvider(PluginProvider pluginProvider) { 32 | this.pluginProvider = pluginProvider; 33 | } 34 | 35 | public List getMappingContextItems() { 36 | return mappingContextItems; 37 | } 38 | 39 | public void addMappingContextItem(ListenerMappingContextItem mappingContextItem) { 40 | if (mappingContextItem != null) this.mappingContextItems.add(mappingContextItem); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "ListenerMappingContext{" + 46 | "pluginProvider=" + pluginProvider + 47 | ", mappingContextItems=" + mappingContextItems + 48 | '}'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/dto/ListenerMappingContextItem.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.dto; 2 | 3 | import com.github.middleware.fsm.builder.event.BaseEvent; 4 | import com.github.middleware.fsm.builder.event.BaseListener; 5 | import com.github.middleware.fsm.builder.event.EventType; 6 | 7 | import java.io.Serializable; 8 | import java.lang.annotation.Annotation; 9 | import java.lang.reflect.Method; 10 | 11 | /** 12 | * @author alex.chen 13 | * @version 1.0.0 14 | * @date 2017/3/20 15 | */ 16 | public class ListenerMappingContextItem implements Serializable { 17 | private EventType eventType; 18 | private Class listenerAn; 19 | private Class listenerClz; 20 | private Class listenerEvent; 21 | //监听状态机事件的函数 22 | private Method listenrMethod; 23 | private Object proxylistenerMethod; 24 | //触发执行函数 25 | private Method firePluginMethod; 26 | private String when; 27 | 28 | public ListenerMappingContextItem(Class listenerAn, Class listenerClz, Class listenerEvent) { 29 | this.listenerAn = listenerAn; 30 | this.listenerEvent = listenerEvent; 31 | this.listenerClz = listenerClz; 32 | } 33 | 34 | public Class getListenerAn() { 35 | return listenerAn; 36 | } 37 | 38 | public void setListenerAn(Class listenerAn) { 39 | this.listenerAn = listenerAn; 40 | } 41 | 42 | public Class getListenerClz() { 43 | return listenerClz; 44 | } 45 | 46 | public void setListenerClz(Class listenerClz) { 47 | this.listenerClz = listenerClz; 48 | } 49 | 50 | public Class getListenerEvent() { 51 | return listenerEvent; 52 | } 53 | 54 | public void setListenerEvent(Class listenerEvent) { 55 | this.listenerEvent = listenerEvent; 56 | } 57 | 58 | public Method getListenrMethod() { 59 | return listenrMethod; 60 | } 61 | 62 | public void setListenrMethod(Method listenrMethod) { 63 | this.listenrMethod = listenrMethod; 64 | } 65 | 66 | public Object getProxylistenerMethod() { 67 | return proxylistenerMethod; 68 | } 69 | 70 | public void setProxylistenerMethod(Object proxylistenerMethod) { 71 | this.proxylistenerMethod = proxylistenerMethod; 72 | } 73 | 74 | public Method getFirePluginMethod() { 75 | return firePluginMethod; 76 | } 77 | 78 | public void setFirePluginMethod(Method firePluginMethod) { 79 | this.firePluginMethod = firePluginMethod; 80 | } 81 | 82 | public String getWhen() { 83 | return when; 84 | } 85 | 86 | public void setWhen(String when) { 87 | this.when = when; 88 | } 89 | 90 | public EventType getEventType() { 91 | return eventType; 92 | } 93 | 94 | public void setEventType(EventType eventType) { 95 | this.eventType = eventType; 96 | } 97 | 98 | @Override 99 | public String toString() { 100 | return "ListenerMappingContextItem{" + 101 | "eventType=" + eventType + 102 | ", listenerAn=" + listenerAn + 103 | ", listenerClz=" + listenerClz + 104 | ", listenerEvent=" + listenerEvent + 105 | ", listenrMethod=" + listenrMethod + 106 | ", proxylistenerMethod=" + proxylistenerMethod + 107 | ", firePluginMethod=" + firePluginMethod + 108 | ", when='" + when + '\'' + 109 | '}'; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/dto/ListenerMethod.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.dto; 2 | 3 | import com.google.common.base.Preconditions; 4 | import com.github.middleware.fsm.builder.event.AsyncEventListener; 5 | import com.github.middleware.fsm.core.factory.ThreadExecutorService; 6 | import com.github.middleware.fsm.core.utils.Precondition; 7 | import com.github.middleware.fsm.core.utils.ReflectUtil; 8 | import com.github.middleware.fsm.exception.StateMachineException; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.io.Serializable; 13 | import java.lang.reflect.Method; 14 | 15 | /** 16 | * @author alex.chen 17 | * @version 1.0.0 18 | * @date 2017/3/8 19 | */ 20 | public class ListenerMethod implements Serializable { 21 | private static final Logger LOGGER = LoggerFactory.getLogger(ListenerMethod.class); 22 | private Class eventType; 23 | private Object target; 24 | private Method method; 25 | private boolean hasParameter = false; 26 | private boolean isAsync; 27 | private long timeout; 28 | 29 | public ListenerMethod(Class eventType, Object listener, Method method) { 30 | Preconditions.checkArgument(eventType != null && listener != null && method != null, "校验异常:入参不能为空!"); 31 | Preconditions.checkArgument(method.getDeclaringClass().isAssignableFrom(listener.getClass()), "校验异常:" + method.getName() + "不适用于 " + listener.getClass().getName()); 32 | this.eventType = eventType; 33 | this.target = listener; 34 | this.method = method; 35 | this.isAsync = AsyncEventListener.class.isAssignableFrom(listener.getClass()); 36 | this.timeout = isAsync ? AsyncEventListener.class.cast(listener).timeout() : -1; 37 | final Class[] params = method.getParameterTypes(); 38 | if (params.length > 0) { 39 | if (params.length == 1 && params[0].isAssignableFrom(eventType)) { 40 | hasParameter = true; 41 | } else { 42 | throw new StateMachineException("校验异常:参数类型异常!"); 43 | } 44 | } 45 | } 46 | 47 | public void invokeMethod(final Object event) { 48 | // LOGGER.info("fsm.fire global event," + JSON.toJSONString(this)); 49 | LOGGER.info("fsm.fire global event," + event); 50 | Precondition.checkState(eventType.isAssignableFrom(event.getClass()), "校验异常:类型不匹配."); 51 | if (isAsync) { 52 | ThreadExecutorService.getExecutor().execute(() -> ReflectUtil.invoke(method, target, hasParameter ? new Object[]{event} : new Object[0])); 53 | } else { 54 | synchronized (target) { 55 | ReflectUtil.invoke(method, target, hasParameter ? new Object[]{event} : new Object[0]); 56 | } 57 | } 58 | } 59 | 60 | public Class getEventType() { 61 | return eventType; 62 | } 63 | 64 | public boolean matches(Class eventType, Object target) { 65 | return (this.target == target) && (eventType.equals(this.eventType)); 66 | } 67 | 68 | public boolean matches(Class eventType, Object target, Method method) { 69 | return (this.target == target) && (eventType.equals(this.eventType) && method.equals(this.method)); 70 | } 71 | 72 | @Override 73 | public boolean equals(Object obj) { 74 | if (this == obj) { 75 | return true; 76 | } 77 | if ((obj == null) || (obj.getClass() != getClass())) { 78 | return false; 79 | } 80 | ListenerMethod t = (ListenerMethod) obj; 81 | return (eventType == t.eventType || (eventType != null && eventType.equals(t.eventType))) 82 | && (target == t.target || (target != null && target.equals(t.target))) 83 | && (method == t.method || (method != null && method.equals(t.method))); 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | return new StringBuilder(target.getClass().getSimpleName()). 89 | append('.').append(method.getName()).append('('). 90 | append(eventType.getSimpleName()).append(')').toString(); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/AbstractExecActionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.ActionEvent; 5 | import com.github.middleware.fsm.builder.exec.Action; 6 | import com.github.middleware.fsm.builder.exec.dto.ExecServiceContext; 7 | import com.github.middleware.fsm.builder.exec.support.ActionImpl; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/14 13 | */ 14 | public abstract class AbstractExecActionEvent, S, E, C> implements ActionEvent { 15 | private ExecServiceContext execServiceContext; 16 | private int pos; 17 | private int size; 18 | 19 | public AbstractExecActionEvent(ExecServiceContext execServiceContext) { 20 | this.execServiceContext = execServiceContext; 21 | } 22 | 23 | public AbstractExecActionEvent(int pos, int size, ExecServiceContext execServiceContext) { 24 | this.pos = pos; 25 | this.size = size; 26 | this.execServiceContext = execServiceContext; 27 | } 28 | 29 | @Override 30 | public Action getExecutionTarget() { 31 | // user can only read action info but cannot invoke action in the listener method 32 | return new ActionImpl(execServiceContext.getAction()); 33 | } 34 | 35 | @Override 36 | public S getFrom() { 37 | return execServiceContext.getFrom(); 38 | } 39 | 40 | @Override 41 | public S getTo() { 42 | return execServiceContext.getTo(); 43 | } 44 | 45 | @Override 46 | public E getEvent() { 47 | return execServiceContext.getEvent(); 48 | } 49 | 50 | @Override 51 | public C getContext() { 52 | return execServiceContext.getContext(); 53 | } 54 | 55 | @Override 56 | public T getStateMachine() { 57 | return execServiceContext.getStateMachine(); 58 | } 59 | 60 | @Override 61 | public int[] getMOfN() { 62 | return new int[]{pos, size}; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/AbstractStateMachineEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.StateMachineEvent; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public abstract class AbstractStateMachineEvent, S, E, C> implements StateMachineEvent { 12 | private T stateMachine; 13 | 14 | public AbstractStateMachineEvent(T stateMachine) { 15 | this.stateMachine = stateMachine; 16 | } 17 | @Override 18 | public T getStateMachine() { 19 | return stateMachine; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/AbstractTransitionEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.TransitionEvent; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public abstract class AbstractTransitionEvent, S, E, C> extends AbstractStateMachineEvent implements TransitionEvent { 12 | private S sourceState; 13 | private E event; 14 | private C context; 15 | 16 | public AbstractTransitionEvent(S sourceState, E event, C context, T stateMachine) { 17 | super(stateMachine); 18 | this.sourceState = sourceState; 19 | this.event = event; 20 | this.context = context; 21 | } 22 | 23 | @Override 24 | public S getSourceState() { 25 | return sourceState; 26 | } 27 | 28 | @Override 29 | public E getCause() { 30 | return event; 31 | } 32 | 33 | @Override 34 | public C getContext() { 35 | return context; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/AfterExecActionEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.event.AfterExecActionEvent; 4 | import com.github.middleware.fsm.builder.StateMachine; 5 | import com.github.middleware.fsm.builder.exec.dto.ExecServiceContext; 6 | 7 | /** 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/3/20 11 | */ 12 | public class AfterExecActionEventImpl, S, E, C> extends AbstractExecActionEvent implements AfterExecActionEvent { 13 | public AfterExecActionEventImpl(ExecServiceContext execServiceContext) { 14 | super(execServiceContext); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/BeforeExecActionEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.event.BeforeExecActionEvent; 4 | import com.github.middleware.fsm.builder.StateMachine; 5 | import com.github.middleware.fsm.builder.exec.dto.ExecServiceContext; 6 | 7 | /** 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/3/14 11 | */ 12 | public class BeforeExecActionEventImpl, S, E, C> extends AbstractExecActionEvent implements BeforeExecActionEvent { 13 | 14 | public BeforeExecActionEventImpl(ExecServiceContext actionContext) { 15 | super(actionContext); 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/ExecActionExceptionEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.ExecActionExceptionEvent; 5 | import com.github.middleware.fsm.builder.exec.dto.ExecServiceContext; 6 | import com.github.middleware.fsm.exception.StateMachineException; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/20 12 | */ 13 | public class ExecActionExceptionEventImpl, S, E, C> extends AbstractExecActionEvent implements ExecActionExceptionEvent { 14 | private StateMachineException e; 15 | 16 | public ExecActionExceptionEventImpl(ExecServiceContext execServiceContext, StateMachineException error) { 17 | super(execServiceContext); 18 | this.e = error; 19 | } 20 | 21 | @Override 22 | public StateMachineException getException() { 23 | return e; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/TransitionBeginEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.event.TransitionBeginEvent; 4 | import com.github.middleware.fsm.builder.StateMachine; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public class TransitionBeginEventImpl, S, E, C> extends AbstractTransitionEvent implements TransitionBeginEvent { 12 | public TransitionBeginEventImpl(S sourceState, E event, C context, T stateMachine) { 13 | super(sourceState, event, context, stateMachine); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/TransitionCompleteEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.TransitionCompleteEvent; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public class TransitionCompleteEventImpl, S, E, C> extends AbstractTransitionEvent implements TransitionCompleteEvent { 12 | private S targetState; 13 | 14 | public TransitionCompleteEventImpl(S sourceState, S targetState, E event, C context, T stateMachine) { 15 | super(sourceState, event, context, stateMachine); 16 | this.targetState = targetState; 17 | } 18 | 19 | @Override 20 | public S getTargetState() { 21 | return targetState; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/TransitionDeclinedEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.TransitionDeclinedEvent; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public class TransitionDeclinedEventImpl, S, E, C> extends AbstractTransitionEvent implements TransitionDeclinedEvent { 12 | public TransitionDeclinedEventImpl(S sourceState, E event, C context, T stateMachine) { 13 | super(sourceState, event, context, stateMachine); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/TransitionEndEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.TransitionEndEvent; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public class TransitionEndEventImpl, S, E, C> extends AbstractTransitionEvent implements TransitionEndEvent { 12 | private S targetState; 13 | 14 | public TransitionEndEventImpl(S sourceState, S targetState, E event, C context, T stateMachine) { 15 | super(sourceState, event, context, stateMachine); 16 | this.targetState = targetState; 17 | } 18 | 19 | @Override 20 | public S getTargetState() { 21 | return targetState; 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/event/support/TransitionExceptionEventImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.event.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.TransitionExceptionEvent; 5 | import com.github.middleware.fsm.exception.StateMachineException; 6 | 7 | /** 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/3/8 11 | */ 12 | public class TransitionExceptionEventImpl, S, E, C> extends AbstractTransitionEvent implements TransitionExceptionEvent { 13 | private S targetState; 14 | private StateMachineException e; 15 | 16 | public TransitionExceptionEventImpl(StateMachineException e, 17 | S sourceState, S targetState, E event, C context, T stateMachine) { 18 | super(sourceState, event, context, stateMachine); 19 | this.targetState = targetState; 20 | this.e = e; 21 | } 22 | 23 | @Override 24 | public S getTargetState() { 25 | return targetState; 26 | } 27 | 28 | @Override 29 | public StateMachineException getException() { 30 | return e; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/Action.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.support.AbstractAction; 5 | 6 | /** 7 | * 执行动作,包含exit、entry、action 8 | * 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/2/27 12 | */ 13 | public interface Action, S, E, C> { 14 | int WEIGHT_NORMAL = 0; 15 | int WEIGHT_BEFORE = 100; 16 | int WEIGHT_AFTER = -100; 17 | int WEIGHT_IGNORE = 1000; 18 | 19 | void execute(S from, S to, E event, C context, T stateMachine, String actionName); 20 | 21 | String getName(); 22 | 23 | /** 24 | * 执行权重 25 | * 26 | * @return 27 | */ 28 | @Deprecated 29 | int weight(); 30 | 31 | /** 32 | * 异步 33 | * 34 | * @return 35 | */ 36 | @Deprecated 37 | boolean isAsync(); 38 | 39 | /** 40 | * 异步超时 41 | * 42 | * @return 43 | */ 44 | @Deprecated 45 | long timeout(); 46 | 47 | 48 | public final static Action DUMMY_ACTION = new AbstractAction() { 49 | @Override 50 | public void execute(Object from, Object to, Object event, 51 | Object context, StateMachine stateMachine, String serviceName) { 52 | // DO NOTHING 53 | } 54 | 55 | @Override 56 | public String getName() { 57 | return "__DUMMY_ACTION"; 58 | } 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/ActionExecService.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.event.BeforeExecActionListener; 5 | import com.github.middleware.fsm.builder.exec.dto.ExecServiceContext; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/8 13 | */ 14 | public interface ActionExecService, S, E, C> { 15 | void execute(ExecServiceContext execServiceContext); 16 | 17 | void addProxyListener(Class eventType, Object listener, Method method); 18 | 19 | void addExecActionListener(BeforeExecActionListener listener); 20 | 21 | void removeExecActionListener(BeforeExecActionListener listener); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/EntryExitBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.chain.When; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/7 10 | */ 11 | public interface EntryExitBuilder, S, E, C> extends When { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/annotation/ExecWhen.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/7 9 | */ 10 | @Deprecated 11 | @Documented 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target({ElementType.TYPE, ElementType.METHOD}) 14 | public @interface ExecWhen { 15 | String value(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/dto/ExecServiceContext.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.dto; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | import com.github.middleware.fsm.builder.machine.support.AbstractStateMachine; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/14 13 | */ 14 | public class ExecServiceContext, S, E, C> implements Serializable { 15 | private String execServiceName; 16 | private Action action; 17 | private S from; 18 | S to; 19 | E event; 20 | C context; 21 | private T stateMachine; 22 | 23 | public ExecServiceContext() { 24 | } 25 | 26 | public S getFrom() { 27 | return from; 28 | } 29 | 30 | public S getTo() { 31 | return to; 32 | } 33 | 34 | public E getEvent() { 35 | return event; 36 | } 37 | 38 | public C getContext() { 39 | return context; 40 | } 41 | 42 | public T getStateMachine() { 43 | return stateMachine; 44 | } 45 | 46 | public Action getAction() { 47 | return action; 48 | } 49 | 50 | public ExecServiceContext setExecServiceName(String execServiceName) { 51 | this.execServiceName = execServiceName; 52 | return this; 53 | } 54 | 55 | public ExecServiceContext setAction(Action action) { 56 | this.action = action; 57 | return this; 58 | } 59 | 60 | public ExecServiceContext setFrom(S from) { 61 | this.from = from; 62 | return this; 63 | } 64 | 65 | public ExecServiceContext setTo(S to) { 66 | this.to = to; 67 | return this; 68 | } 69 | 70 | public ExecServiceContext setEvent(E event) { 71 | this.event = event; 72 | return this; 73 | } 74 | 75 | public ExecServiceContext setContext(C context) { 76 | this.context = context; 77 | return this; 78 | } 79 | 80 | public ExecServiceContext setStateMachine(T stateMachine) { 81 | this.stateMachine = stateMachine; 82 | return this; 83 | } 84 | 85 | /** 86 | * 执行 87 | * TODO:有的污染需改造 88 | */ 89 | public void doAction() { 90 | AbstractStateMachine fsmImpl = (AbstractStateMachine) stateMachine; 91 | fsmImpl.beforeActionInvoked(from, to, event, context); 92 | action.execute(from, to, event, context, stateMachine,execServiceName); 93 | 94 | fsmImpl.afterActionInvoked(from, to, event, context); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/dto/RegularTransition.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.dto; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/7 13 | */ 14 | public class RegularTransition, S, E, C> implements Serializable { 15 | private List> actions; 16 | 17 | private S from; 18 | 19 | private S to; 20 | 21 | private E event; 22 | 23 | public RegularTransition(S from, S to, E event) { 24 | this.from = from; 25 | this.to = to; 26 | this.event = event; 27 | } 28 | 29 | public S getFrom() { 30 | return from; 31 | } 32 | 33 | public S getTo() { 34 | return to; 35 | } 36 | 37 | public E getEvent() { 38 | return event; 39 | } 40 | 41 | public List> getActions() { 42 | return actions; 43 | } 44 | 45 | public void setActions(List> actions) { 46 | this.actions = actions; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/dto/RuleExecContext.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.dto; 2 | 3 | import com.github.middleware.fsm.core.el.MvelScriptManager; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/7 12 | */ 13 | public class RuleExecContext implements Serializable { 14 | private MvelScriptManager scriptManager; 15 | private Class executionTargetType; 16 | private Class[] methodCallParamTypes; 17 | 18 | public RuleExecContext(MvelScriptManager scriptManager, Class executionTargetType, Class[] methodCallParamTypes) { 19 | this.scriptManager = scriptManager; 20 | this.executionTargetType = executionTargetType; 21 | this.methodCallParamTypes = methodCallParamTypes; 22 | } 23 | 24 | public MvelScriptManager getScriptManager() { 25 | return scriptManager; 26 | } 27 | 28 | public Class getExecutionTargetType() { 29 | return executionTargetType; 30 | } 31 | 32 | public Class[] getMethodCallParamTypes() { 33 | return methodCallParamTypes; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/support/AbstractAction.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/7 10 | */ 11 | public abstract class AbstractAction, S, E, C> implements Action { 12 | 13 | @Override 14 | public String getName() { 15 | return getClass().getSimpleName() + "_Action"; 16 | } 17 | 18 | @Override 19 | public int weight() { 20 | return WEIGHT_NORMAL; 21 | } 22 | 23 | @Override 24 | final public String toString() { 25 | return "instance#" + getClass().getName(); 26 | } 27 | 28 | @Override 29 | public boolean isAsync() { 30 | return false; 31 | } 32 | 33 | @Override 34 | public long timeout() { 35 | return -1; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/support/ActionExecServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.config.application.StateMachineConfig; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/8 10 | */ 11 | public class ActionExecServiceImpl, S, E, C> extends AbstractExecService { 12 | public ActionExecServiceImpl(StateMachineConfig config) { 13 | super(config); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/support/ActionImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | import com.github.middleware.fsm.exception.StateMachineException; 6 | 7 | /** 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/3/14 11 | */ 12 | public class ActionImpl, S, E, C> extends AbstractAction { 13 | private Action action; 14 | 15 | public ActionImpl(Action action) { 16 | this.action = action; 17 | } 18 | 19 | @Override 20 | public void execute(S from, S to, E event, C context, T stateMachine, String actionName) { 21 | throw new StateMachineException("未发生任何调用."); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/support/ActionWrapper.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/7 10 | */ 11 | public class ActionWrapper, S, E, C> implements Action { 12 | private Action delegator; 13 | 14 | public ActionWrapper(Action delegator) { 15 | this.delegator = delegator; 16 | } 17 | 18 | @Override 19 | public void execute(S from, S to, E event, C context, T stateMachine,String actionName) { 20 | delegator.execute(from, to, event, context, stateMachine,actionName); 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return delegator.getName(); 26 | } 27 | 28 | @Override 29 | public int weight() { 30 | return delegator.weight(); 31 | } 32 | 33 | @Override 34 | public long timeout() { 35 | return delegator.timeout(); 36 | } 37 | 38 | @Override 39 | public boolean isAsync() { 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/support/EntryExitBuilderImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.support; 2 | 3 | import com.github.middleware.fsm.builder.exec.dto.RuleExecContext; 4 | import com.github.middleware.fsm.builder.state.StateDefine; 5 | import com.github.middleware.fsm.builder.StateMachine; 6 | import com.github.middleware.fsm.builder.StateMachines; 7 | import com.github.middleware.fsm.builder.exec.Action; 8 | import com.github.middleware.fsm.builder.exec.EntryExitBuilder; 9 | 10 | /** 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/3/7 14 | */ 15 | public class EntryExitBuilderImpl, S, E, C> implements EntryExitBuilder { 16 | private boolean isEntryAction; 17 | private StateDefine state; 18 | private RuleExecContext execContext; 19 | 20 | public EntryExitBuilderImpl() { 21 | 22 | } 23 | 24 | public EntryExitBuilderImpl(StateDefine state, boolean isEntryAction, RuleExecContext execContext) { 25 | this.isEntryAction = isEntryAction; 26 | this.state = state; 27 | this.execContext = execContext; 28 | } 29 | 30 | @Override 31 | public void complete(Action action) { 32 | if (isEntryAction) { 33 | state.addEntryAction(action); 34 | } else { 35 | state.addExitAction(action); 36 | } 37 | } 38 | @Override 39 | public void complete(String callMethod) { 40 | Action action = StateMachines.newMethodCallActionProxy(callMethod, execContext); 41 | complete(action); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/support/MethodCallImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.support; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import com.github.middleware.fsm.builder.exec.dto.RuleExecContext; 5 | import com.google.common.base.Stopwatch; 6 | import com.google.common.base.Strings; 7 | import com.google.common.collect.Lists; 8 | import com.github.middleware.fsm.builder.StateMachine; 9 | import com.github.middleware.fsm.core.utils.ReflectUtil; 10 | import com.github.middleware.fsm.builder.exec.Action; 11 | import com.github.middleware.fsm.builder.plugin.log.LogExec; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.lang.reflect.Method; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | /** 20 | * 方法调用 21 | * 22 | * @author alex.chen 23 | * @version 1.0.0 24 | * @date 2017/3/7 25 | */ 26 | public class MethodCallImpl, S, E, C> implements Action { 27 | private static final Logger LOGGER = LoggerFactory.getLogger(MethodCallImpl.class); 28 | private Method method; 29 | private boolean logExec; 30 | private String scriptExpr; 31 | private int weight; 32 | @JSONField(serialize = false) 33 | private RuleExecContext execContext; 34 | private String serviceName; 35 | 36 | public MethodCallImpl(Method method, int weight, RuleExecContext execContext) { 37 | this.method = method; 38 | this.weight = Action.WEIGHT_NORMAL; 39 | this.execContext = execContext; 40 | if (method != null) { 41 | LogExec logExecObj = method.getAnnotation(LogExec.class); 42 | if (logExecObj != null) { 43 | if (!Strings.isNullOrEmpty(logExecObj.when())) { 44 | logExec = true; 45 | scriptExpr = logExecObj.when(); 46 | this.execContext.getScriptManager().compile(scriptExpr); 47 | } 48 | } 49 | } 50 | } 51 | 52 | @Override 53 | public void execute(S from, S to, E event, C context, T stateMachine, String serviceName) { 54 | this.serviceName = serviceName; 55 | Object[] paramValues = Lists.newArrayList(from, to, event, context).subList(0, execContext.getMethodCallParamTypes().length).toArray(); 56 | // LOGGER.info("fsm.fire exec start,method:" + methodToString(this.method) + ",scriptExpr:" + scriptExpr + ",paramValues:" + paramValues); 57 | if (scriptExpr != null) { 58 | Map variables = new HashMap(); 59 | variables.put("context", context); 60 | boolean isAllowed = execContext.getScriptManager().evalBoolean(scriptExpr, variables); 61 | if (!isAllowed) return; 62 | } 63 | if (logExec) { 64 | Stopwatch sw = Stopwatch.createStarted(); 65 | ReflectUtil.invoke(method, stateMachine, paramValues); 66 | LOGGER.info("fsm.fire exec," + getName() + " times:" + sw); 67 | } else { 68 | ReflectUtil.invoke(method, stateMachine, paramValues); 69 | } 70 | } 71 | 72 | @Override 73 | public String getName() { 74 | return serviceName + "." + method; 75 | } 76 | 77 | @Override 78 | public int weight() { 79 | return 0; 80 | } 81 | 82 | @Override 83 | public long timeout() { 84 | return 0; 85 | } 86 | 87 | @Override 88 | public boolean isAsync() { 89 | return false; 90 | } 91 | 92 | private String methodToString(Method method) { 93 | if (method == null) 94 | return null; 95 | StringBuilder builder = new StringBuilder(method.getDeclaringClass().getSimpleName()); 96 | builder.append('.').append(method.getName()).append('('); 97 | if (method.getParameterTypes() != null) { 98 | for (int i = 0, size = method.getParameterTypes().length; i < size; ++i) { 99 | if (i != 0) builder.append(", "); 100 | builder.append(method.getParameterTypes()[i].getSimpleName()); 101 | } 102 | } 103 | builder.append(')'); 104 | return builder.toString(); 105 | } 106 | 107 | @Override 108 | public String toString() { 109 | return "MethodCallImpl{" + 110 | "method=" + method + 111 | ", logExec=" + logExec + 112 | ", scriptExpr='" + scriptExpr + '\'' + 113 | ", weight=" + weight + 114 | ", serviceName='" + serviceName + '\'' + 115 | '}'; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/exec/support/MethodCallProxyImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.exec.support; 2 | 3 | import com.github.middleware.fsm.builder.exec.dto.RuleExecContext; 4 | import com.github.middleware.fsm.builder.machine.support.AbstractStateMachine; 5 | import com.github.middleware.fsm.builder.StateMachine; 6 | import com.github.middleware.fsm.builder.StateMachines; 7 | import com.github.middleware.fsm.core.utils.Precondition; 8 | import com.github.middleware.fsm.core.utils.ReflectUtil; 9 | import com.github.middleware.fsm.builder.exec.Action; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.lang.reflect.Method; 15 | 16 | /** 17 | * 方法调用代理 18 | * TODO:根据方法名支持更多执行策略,比如:ignore/before/after 19 | * 20 | * @author alex.chen 21 | * @version 1.0.0 22 | * @date 2017/3/7 23 | */ 24 | public class MethodCallProxyImpl, S, E, C> implements Action { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(MethodCallProxyImpl.class); 26 | private String methodName; 27 | private RuleExecContext execContext; 28 | private Action delegator; 29 | private int weight; 30 | private long timeout; 31 | 32 | /** 33 | * @param methodName 34 | * @param execContext 35 | */ 36 | public MethodCallProxyImpl(String methodName, RuleExecContext execContext) { 37 | this.methodName = methodName; 38 | this.execContext = execContext; 39 | this.weight = Action.WEIGHT_NORMAL; 40 | } 41 | 42 | @Override 43 | public void execute(S from, S to, E event, C context, T stateMachine,String actionName) { 44 | Precondition.checkNotNull(stateMachine, "校验异常:状态机实现类不能为空."); 45 | getDelegator().execute(from, to, event, context, stateMachine, actionName); 46 | } 47 | 48 | private Action getDelegator() { 49 | if (delegator == null) { 50 | Method method = ReflectUtil.searchMethod(execContext.getExecutionTargetType(), AbstractStateMachine.class, methodName, execContext.getMethodCallParamTypes()); 51 | if (method != null) { 52 | delegator = StateMachines.newMethodCallAction(method, weight, execContext); 53 | } else { 54 | if (LOGGER.isInfoEnabled()) { 55 | LOGGER.info("未找到方法 '" + methodName + "' 参数 '[" + StringUtils.join(execContext.getMethodCallParamTypes(), ", ") + "]' in class " + execContext.getExecutionTargetType() + "."); 56 | } 57 | delegator = (Action) Action.DUMMY_ACTION; 58 | } 59 | } 60 | return delegator; 61 | } 62 | 63 | @Override 64 | public String getName() { 65 | return methodName; 66 | } 67 | 68 | @Override 69 | public int weight() { 70 | return this.weight; 71 | } 72 | 73 | @Override 74 | public long timeout() { 75 | return this.timeout; 76 | } 77 | 78 | @Override 79 | public boolean isAsync() { 80 | return false; 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/StateMachineBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.chain.LocalTransitionBuilder; 5 | import com.github.middleware.fsm.builder.exec.EntryExitBuilder; 6 | import com.github.middleware.fsm.builder.plugin.PluginBuilder; 7 | import com.github.middleware.fsm.builder.plugin.PluginProvider; 8 | import com.github.middleware.fsm.config.application.StateMachineConfig; 9 | 10 | /** 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/3/6 14 | */ 15 | public interface StateMachineBuilder, S, E, C> { 16 | LocalTransitionBuilder localTransition(); 17 | 18 | T newStateMachine(); 19 | 20 | T newStateMachine(S initialStateName); 21 | 22 | T newStateMachine(S initialStateName, Object... extraParams); 23 | 24 | @Deprecated 25 | T newStateMachine(T fsmBean, S initialStateName, StateMachineConfig configuration, Object... extraParams); 26 | 27 | EntryExitBuilder onEntry(S stateName); 28 | 29 | EntryExitBuilder onExit(S stateName); 30 | 31 | PluginBuilder newPluginBuilder(PluginProvider pluginProvider); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/annotation/HoldPayload.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 是否携带Payload 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/7 10 | */ 11 | @Documented 12 | @Retention(value = RetentionPolicy.RUNTIME) 13 | @Target(ElementType.TYPE) 14 | public @interface HoldPayload { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/dto/RequestPayload.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.dto; 2 | 3 | 4 | /** 5 | * 请求报文 6 | * 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/2/27 10 | */ 11 | @Deprecated 12 | public abstract class RequestPayload { 13 | @Override 14 | public String toString() { 15 | return getRequestPayloadMsg(); 16 | } 17 | 18 | public abstract String getRequestPayloadMsg(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/dto/StateMachineContext.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.dto; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.Stack; 7 | 8 | /** 9 | * 状态机上下文环境 10 | * 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/2/27 14 | */ 15 | public class StateMachineContext { 16 | private static final Logger LOGGER = LoggerFactory.getLogger(StateMachineContext.class); 17 | private Object currentInstance; 18 | private boolean isTestEvent; 19 | 20 | private StateMachineContext() { 21 | } 22 | 23 | public StateMachineContext(Object stateMachine, boolean isTestEvent) { 24 | this.currentInstance = stateMachine; 25 | this.isTestEvent = isTestEvent; 26 | } 27 | 28 | private static final ThreadLocal> contextContainer = new ThreadLocal>() { 29 | @Override 30 | protected Stack initialValue() { 31 | return new Stack(); 32 | } 33 | }; 34 | 35 | public static void setTnstance(Object instance) { 36 | setTnstance(instance, false); 37 | } 38 | 39 | public static void setTnstance(Object instance, boolean isTestEvent) { 40 | if (instance == null) { 41 | contextContainer.get().pop(); 42 | } else { 43 | contextContainer.get().push(new StateMachineContext(instance, isTestEvent)); 44 | } 45 | } 46 | 47 | public static T getTnstance() { 48 | return contextContainer.get().size() > 0 ? (T) contextContainer.get().peek().currentInstance : null; 49 | } 50 | 51 | public static boolean isTestEvent() { 52 | return contextContainer.get().size() > 0 ? contextContainer.get().peek().isTestEvent : false; 53 | } 54 | 55 | public static void removeContext() { 56 | contextContainer.remove(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/factroy/StateMachineBuilderFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.factroy; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.machine.StateMachineBuilder; 5 | import com.github.middleware.fsm.builder.machine.support.visit.StateMachineBuilderProxy; 6 | import com.github.middleware.fsm.builder.machine.support.visit.StateMachineProxy; 7 | import com.github.middleware.fsm.config.application.StateMachineConfig; 8 | import com.github.middleware.fsm.core.factory.DependProvider; 9 | import com.github.middleware.fsm.core.types.TypeReference; 10 | import com.github.middleware.fsm.exception.StateMachineException; 11 | 12 | import java.lang.reflect.InvocationHandler; 13 | import java.lang.reflect.InvocationTargetException; 14 | import java.lang.reflect.Method; 15 | import java.lang.reflect.Proxy; 16 | 17 | /** 18 | * @author alex.chen 19 | * @version 1.0.0 20 | * @date 2017/3/6 21 | */ 22 | public class StateMachineBuilderFactory { 23 | /** 24 | * 根据ProxyStateMachine来创建 25 | * 26 | * @param fsmClazz 27 | * @return 28 | */ 29 | public static StateMachineBuilderProxy create(Class fsmClazz) { 30 | return create(fsmClazz, new Class[0]); 31 | } 32 | 33 | /** 34 | * 根据ProxyStateMachine来创建 35 | * 36 | * @param fsmClazz 37 | * @param paramTypes 38 | * @return 39 | */ 40 | public static StateMachineBuilderProxy create(Class fsmClazz, 41 | Class... paramTypes) { 42 | final StateMachineBuilder builder = 43 | create(fsmClazz, Object.class, Object.class, Object.class, paramTypes); 44 | return (StateMachineBuilderProxy) Proxy.newProxyInstance( 45 | StateMachineBuilderProxy.class.getClassLoader(), 46 | new Class[]{StateMachineBuilderProxy.class}, 47 | new InvocationHandler() { 48 | @Override 49 | public Object invoke(Object proxy, Method method, Object[] args) 50 | throws Throwable { 51 | try { 52 | String methodName = method.getName(); 53 | if (methodName.equals("newDefaultStateMachine") || methodName.equals("newSoftStateMachine")) { 54 | Object fsmInstance = null; 55 | if (args.length == 3 && StateMachineConfig.class.isAssignableFrom(args[1].getClass()) && 56 | (args[2] == null || args[2].getClass().isArray())) { 57 | fsmInstance = builder.newStateMachine(args[0], (StateMachineConfig) args[1], (Object[]) args[2]); 58 | } else if (args.length == 2 && (args[1] == null || args[1].getClass().isArray())) { 59 | fsmInstance = builder.newStateMachine(args[0], (Object[]) args[1]); 60 | } else if (args.length == 1) { 61 | fsmInstance = builder.newStateMachine(args[0]); 62 | } else { 63 | throw new StateMachineException("Illegal argument number."); 64 | } 65 | return fsmInstance; 66 | } 67 | return method.invoke(builder, args); 68 | } catch (InvocationTargetException e) { 69 | throw e.getTargetException(); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | 76 | /** 77 | * 根据AbstractStateMachine来创建 78 | * 79 | * @param fsmClazz 80 | * @param stateClazz 81 | * @param eventClazz 82 | * @param contextClazz 83 | * @param extraConstParamTypes 84 | * @param 85 | * @param 86 | * @param 87 | * @param 88 | * @return 89 | */ 90 | public static , S, E, C> StateMachineBuilder create( 91 | Class fsmClazz, Class stateClazz, Class eventClazz, Class contextClazz, 92 | Class... extraConstParamTypes) { 93 | return DependProvider.getInstance().newInstance(new TypeReference>() { 94 | }, 95 | new Class[]{Class.class, Class.class, Class.class, Class.class, Class[].class}, 96 | new Object[]{fsmClazz, stateClazz, eventClazz, contextClazz, extraConstParamTypes}); 97 | } 98 | 99 | public static , S, E, C> StateMachineBuilder create( 100 | Class stateMachineClazz, Class stateClazz, Class eventClazz, Class contextClazz) { 101 | return create(stateMachineClazz, stateClazz, eventClazz, contextClazz, new Class[0]); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/support/AbstractSubject.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.support; 2 | 3 | import com.github.middleware.fsm.builder.event.BaseEvent; 4 | import com.github.middleware.fsm.builder.event.dto.ListenerMethod; 5 | import com.google.common.base.Predicate; 6 | import com.google.common.collect.Iterators; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.lang.reflect.Method; 11 | import java.util.LinkedHashSet; 12 | 13 | /** 14 | * 向FSM中添加事件监听 15 | * 16 | * @author alex.chen 17 | * @version 1.0.0 18 | * @date 2017/3/8 19 | */ 20 | public abstract class AbstractSubject { 21 | private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSubject.class); 22 | private LinkedHashSet listeners = null; 23 | 24 | /** 25 | * 触发事件 26 | * 27 | * @param event 28 | */ 29 | protected void fireEvent(BaseEvent event) { 30 | if (listeners == null) return; 31 | ListenerMethod[] listenerArray = listeners.toArray(new ListenerMethod[listeners.size()]); 32 | for (int i = 0; i < listenerArray.length; i++) { 33 | if (listenerArray[i].getEventType().isAssignableFrom(event.getClass())) { 34 | listenerArray[i].invokeMethod(event); 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * 添加事件监听 41 | * 42 | * @param eventType 43 | * @param listener 44 | * @param method 45 | */ 46 | protected void addListener(Class eventType, Object listener, Method method) { 47 | register(eventType, listener, method); 48 | } 49 | 50 | /** 51 | * 删除监听 52 | * 53 | * @param eventType 54 | * @param listener 55 | * @param method 56 | */ 57 | protected void removeListener(Class eventType, Object listener, Method method) { 58 | if (listeners != null) { 59 | ListenerMethod toBeRemove = Iterators.find(listeners.iterator(), new Predicate() { 60 | @Override 61 | public boolean apply(ListenerMethod m) { 62 | return m.matches(eventType, listener, method); 63 | } 64 | }); 65 | if (toBeRemove != null) { 66 | listeners.remove(toBeRemove); 67 | } 68 | } 69 | } 70 | 71 | protected void removeListener(Class eventType, Object listener) { 72 | if (listeners != null) { 73 | Iterators.removeIf(listeners.iterator(), new Predicate() { 74 | @Override 75 | public boolean apply(ListenerMethod m) { 76 | return m.matches(eventType, listener); 77 | } 78 | }); 79 | } 80 | } 81 | 82 | /** 83 | * 添加事件监听 84 | * 85 | * @param eventType 86 | * @param listener 87 | * @param method 88 | */ 89 | private void register(Class eventType, Object listener, Method method) { 90 | if (!enableEventListener()) { 91 | LOGGER.warn("addListener失败,未开启相应配置"); 92 | return; 93 | } 94 | if (listeners == null) { 95 | listeners = new LinkedHashSet(); 96 | } 97 | listeners.add(new ListenerMethod(eventType, listener, method)); 98 | } 99 | 100 | protected abstract boolean enableEventListener(); 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/support/visit/AbstractStateMachineProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.support.visit; 2 | 3 | import com.github.middleware.fsm.builder.machine.support.AbstractStateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/12 9 | */ 10 | public abstract class AbstractStateMachineProxy extends AbstractStateMachine implements StateMachineProxy { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/support/visit/DefaultStateMachineBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.support.visit; 2 | 3 | import com.github.middleware.fsm.builder.machine.StateMachineBuilder; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/6 9 | */ 10 | @Deprecated 11 | public interface DefaultStateMachineBuilder extends StateMachineBuilder { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/support/visit/StateMachineBuilderProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.support.visit; 2 | 3 | import com.github.middleware.fsm.config.application.StateMachineConfig; 4 | import com.github.middleware.fsm.builder.machine.StateMachineBuilder; 5 | 6 | /** 7 | * Created by YT on 2017/3/12. 8 | */ 9 | public interface StateMachineBuilderProxy extends StateMachineBuilder { 10 | T newDefaultStateMachine(Object initialStateId); 11 | 12 | T newDefaultStateMachine(Object initialStateId, Object... extraParams); 13 | 14 | T newDefaultStateMachine( 15 | Object initialStateId, StateMachineConfig configuration, Object... extraParams); 16 | 17 | T newSoftStateMachine(Object initialStateId); 18 | 19 | T newSoftStateMachine(Object initialStateId, Object... extraParams); 20 | 21 | T newSoftStateMachine(Object initialStateId, StateMachineConfig configuration, Object... extraParams); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/machine/support/visit/StateMachineProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.machine.support.visit; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/12 9 | */ 10 | public interface StateMachineProxy extends StateMachine { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/plugin/PluginBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.plugin; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * Created by YT on 2017/3/17. 7 | */ 8 | public interface PluginBuilder, S, E, C> extends PluginLiftcycle { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/plugin/PluginLiftcycle.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.plugin; 2 | 3 | /** 4 | * Created by YT on 2017/3/15. 5 | */ 6 | public interface PluginLiftcycle { 7 | void install(); 8 | void unInstall(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/plugin/PluginProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.plugin; 2 | 3 | import com.github.middleware.fsm.core.Singletonable; 4 | 5 | /** 6 | * Created by YT on 2017/3/15. 7 | */ 8 | public interface PluginProvider extends Singletonable{ 9 | String getPluginName(); 10 | String setFsmId(String fsmId); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/plugin/log/LogExec.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.plugin.log; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 记录执行时间 7 | * Debug模式 8 | * 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/7 12 | */ 13 | @Documented 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.TYPE, ElementType.METHOD}) 16 | public @interface LogExec { 17 | //when mvel 18 | String when() default "1==1"; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/plugin/log/support/FsmListenerLogger.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.plugin.log.support; 2 | 3 | import com.github.middleware.fsm.builder.event.annotation.*; 4 | import com.github.middleware.fsm.builder.exec.Action; 5 | import com.github.middleware.fsm.builder.plugin.PluginProvider; 6 | import com.github.middleware.fsm.exception.StateMachineException; 7 | import com.google.common.base.Stopwatch; 8 | import com.github.middleware.fsm.builder.plugin.support.AbstractPluginProvider; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * @author alex.chen 14 | * @version 1.0.0 15 | * @date 2017/3/15 16 | */ 17 | 18 | public class FsmListenerLogger extends AbstractPluginProvider implements PluginProvider { 19 | private static final Logger LOGGER = LoggerFactory.getLogger(FsmListenerLogger.class); 20 | private Stopwatch transitionWatch; 21 | private Stopwatch actionWatch; 22 | 23 | public FsmListenerLogger() { 24 | name = "log"; 25 | } 26 | @OnTransitionBegin 27 | public void onTransitionBegin(Object from, Object event, Object context) { 28 | transitionWatch = Stopwatch.createStarted(); 29 | LOGGER.info(fsmId + ": 扭转 from[" + from + "] on [" + event + "] with context [" + context + "] begin."); 30 | } 31 | 32 | @OnTransitionComplete 33 | public void onTransitionComplete(Object sourceState, Object targetState, Object event, Object context) { 34 | LOGGER.info(fsmId + ": 扭转 from [" + sourceState + "] to [" + targetState + "] on [" + event + "] complete which took " + transitionWatch + "."); 35 | } 36 | 37 | @OnTransitionDecline 38 | public void onTransitionDeclined(Object sourceState, Object event) { 39 | LOGGER.info(fsmId + ": 扭转 from [" + sourceState + "] on [" + event + "] 拒绝."); 40 | } 41 | 42 | @OnTransitionException 43 | public void onTransitionException(Object sourceState, Object targetState, Object event, Object context, StateMachineException e) { 44 | Throwable expcetion = e.getTargetException(); 45 | LOGGER.error(fsmId + ": 扭转 from [" + sourceState + "] to [" + targetState + "] on [" + event + "] 发送异常.", expcetion); 46 | } 47 | 48 | @OnBeforeAction(when = "1==2") 49 | public void onBeforeActionExecuted(Object sourceState, Object targetState, 50 | Object event, Object context, int[] mOfN, Action action) { 51 | actionWatch = Stopwatch.createStarted(); 52 | LOGGER.info("方法调用前 [" + action.getName() + "]:" + action.weight() + " (" + mOfN[0] + " of " + mOfN[1] + ")."); 53 | } 54 | 55 | @OnAfterAction(when = "1==1") 56 | public void onAfterActionExecuted(Object sourceState, Object targetState, 57 | Object event, Object context, int[] mOfN, Action action) { 58 | LOGGER.info("方法调用后 [" + action.getName() + "]:" + action.weight() + " which took " + actionWatch + "."); 59 | } 60 | 61 | @OnActionException 62 | public void onActionExecException(Action action, StateMachineException e) { 63 | LOGGER.error("方法调用异常 [" + action.getName() + "] caused by " + e.getMessage()); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/plugin/support/AbstractPluginProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.plugin.support; 2 | 3 | import com.github.middleware.fsm.builder.plugin.PluginProvider; 4 | import com.github.middleware.fsm.filter.annotation.PostConstruct; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/17 10 | */ 11 | public abstract class AbstractPluginProvider implements PluginProvider { 12 | protected String name; 13 | protected String fsmId; 14 | 15 | @Override 16 | public String getPluginName() { 17 | return "plugin_" + name; 18 | } 19 | 20 | /** 21 | * 暂时不需要整个状态机注入 22 | * @param fsmId 23 | * @return 24 | */ 25 | @PostConstruct 26 | public String setFsmId(String fsmId) { 27 | return this.fsmId = fsmId; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/selector/QueueStrategy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.selector; 2 | 3 | 4 | /** 5 | * 非线程安全模式下(队列策略) 6 | * 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/2/28 10 | */ 11 | @Deprecated 12 | public class QueueStrategy { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/selector/ReentrantLockStrategy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.selector; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | /** 9 | * 非线程安全模式下(排他锁策略) 10 | * 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/2/28 14 | */ 15 | @Deprecated 16 | public class ReentrantLockStrategy{ 17 | private static final Logger LOGGER = LoggerFactory.getLogger(ReentrantLockStrategy.class); 18 | private ReentrantLock lock = new ReentrantLock(); 19 | 20 | public ReentrantLockStrategy() { 21 | } 22 | 23 | // @Override 24 | // public void handleEvent(E event, Dispatcher dispatcher) { 25 | // try { 26 | // lock.tryLock(0, TimeUnit.SECONDS); 27 | // List> transitions = dispatcher.getCurrentState().getTransitions(); 28 | // for (TransitionDefine transition : transitions) { 29 | // if (!isPassAllChecker(transition, event, dispatcher.getRequestPayload())) { 30 | // continue; 31 | // } 32 | // AbstractState newState = transition.getToState(); 33 | // LOGGER.info("状态扭转链:" + dispatcher.getCurrentState().getName() + " => " + newState.getName() + " exec"); 34 | // doActions(newState, transition.getActionList(), dispatcher); 35 | // dispatcher.setCurrentState(newState); 36 | // isFired = true; 37 | // break; 38 | // } 39 | // } catch (InterruptedException ie) { 40 | // LOGGER.warn("handleEvent: interrupted exception"); 41 | // } finally { 42 | // lock.unlock(); 43 | // } 44 | // } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/selector/SingleStrategy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.selector; 2 | 3 | /** 4 | * 线程安全(单例模式策略) 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/2/28 9 | */ 10 | @Deprecated 11 | public class SingleStrategy{ 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/selector/StateMachineStrategy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.selector; 2 | 3 | 4 | /** 5 | * 状态机加载执行策略 6 | * 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/2/27 10 | */ 11 | @Deprecated 12 | public interface StateMachineStrategy { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/ImmutableLinkedState.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * Created by YT on 2017/3/8. 7 | */ 8 | public interface ImmutableLinkedState, S, E, C> extends StateDefine { 9 | 10 | /** 11 | * @return linked state machine 12 | */ 13 | StateMachine, S, E, C> getLinkedStateMachine(T stateMachine); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/StateActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.state.dto.StateContext; 5 | 6 | /** 7 | * 状态进入/退出 8 | * Created by YT on 2017/3/8. 9 | */ 10 | public interface StateActivity, S, E, C> { 11 | /** 12 | * 触发状态监测 13 | * 14 | * @param stateContext 15 | */ 16 | void fireInternal(StateContext stateContext); 17 | 18 | /** 19 | * 执行exit action 20 | * 21 | * @param stateContext 22 | */ 23 | void exit(StateContext stateContext); 24 | 25 | /** 26 | * 执行entry action 27 | * 28 | * @param stateContext 29 | */ 30 | void enter(StateContext stateContext); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/StateCriteria.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state; 2 | 3 | 4 | import com.github.middleware.fsm.builder.StateMachine; 5 | import com.github.middleware.fsm.core.el.Dsl; 6 | import com.github.middleware.fsm.builder.chain.TransitionDefine; 7 | import com.github.middleware.fsm.builder.state.support.AbstractState; 8 | 9 | /** 10 | * State链式语法支持 11 | * 12 | * @author alex.chen 13 | * @version 1.0.0 14 | * @date 2017/2/27 15 | */ 16 | 17 | public interface StateCriteria, S, E, C> extends Dsl { 18 | AbstractState choice(S name); 19 | 20 | TransitionDefine from(S S); 21 | 22 | TransitionDefine fromChoice(S choiceName); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/StateDefine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | import com.github.middleware.fsm.builder.chain.TransitionDefine; 5 | 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | /** 10 | * 状态定义 11 | * 12 | * @param 状态值 13 | * @param 事件值 14 | * @author alex.chen 15 | * @version 1.0.0 16 | * @date 2017/2/27 17 | */ 18 | public interface StateDefine, S, E, C> extends StateLiftcycle { 19 | void setLevel(int level); 20 | void setParentState(StateDefine parent); 21 | void setInitialState(StateDefine childInitialState); 22 | void setEndState(boolean endState); 23 | void addChildState(StateDefine childState); 24 | //向from节点添加扭转链(针对on语法) 25 | TransitionDefine addTransitionOn(E event); 26 | void check(); 27 | 28 | //todo: 29 | S getName(); 30 | int getLevel(); 31 | StateDefine getParentState(); 32 | StateDefine getInitialState(); 33 | boolean isEndState(); 34 | List> getChildStates(); 35 | boolean hasChildStates(); 36 | boolean isRootState(); 37 | List> getTransitions(); 38 | List> getTransitions(E event); 39 | StateDefine self(); 40 | String getPath(); 41 | Set getEvents(); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/StateLiftcycle.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state; 2 | 3 | import com.github.middleware.fsm.builder.state.support.AbstractState; 4 | import com.github.middleware.fsm.builder.StateMachine; 5 | import com.github.middleware.fsm.builder.exec.Action; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 状态生命周期(退出&进入) 11 | * 12 | * @author alex.chen 13 | * @version 1.0.0 14 | * @date 2017/2/27 15 | */ 16 | public interface StateLiftcycle, S, E, C> extends StateActivity { 17 | AbstractState addEntryAction(Action entryAction); 18 | AbstractState addExitAction(Action exitAction); 19 | 20 | List> getEntryActions(); 21 | List> getExitActions(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/dto/StateContext.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state.dto; 2 | 3 | import com.github.middleware.fsm.builder.state.StateDefine; 4 | import com.github.middleware.fsm.builder.StateMachine; 5 | import com.github.middleware.fsm.builder.chain.dto.TransitionResult; 6 | import com.github.middleware.fsm.builder.exec.ActionExecService; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/3/8 14 | */ 15 | public class StateContext, S, E, C> implements Serializable { 16 | private StateMachine stateMachine; 17 | private StateDefine fromState; 18 | private C context; 19 | private E event; 20 | private TransitionResult result; 21 | private ActionExecService executor; 22 | 23 | public StateContext(StateMachine stateMachine, 24 | StateDefine fromState, E event, C context, 25 | TransitionResult result, ActionExecService executor) { 26 | this.stateMachine = stateMachine; 27 | this.fromState = fromState; 28 | this.event = event; 29 | this.context = context; 30 | this.result = result; 31 | this.executor = executor; 32 | } 33 | 34 | public StateMachine getStateMachine() { 35 | return stateMachine; 36 | } 37 | 38 | public StateDefine getFromState() { 39 | return fromState; 40 | } 41 | 42 | public C getContext() { 43 | return context; 44 | } 45 | 46 | public E getEvent() { 47 | return event; 48 | } 49 | 50 | public TransitionResult getResult() { 51 | return result; 52 | } 53 | 54 | public ActionExecService getExecutor() { 55 | return executor; 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/support/ChoiceStateDefine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/2/28 9 | */ 10 | @Deprecated 11 | public class ChoiceStateDefine, S, E, C> extends AbstractState { 12 | public ChoiceStateDefine(S name) { 13 | super(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/support/SimpleStateDefine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/2/28 9 | */ 10 | @Deprecated 11 | public class SimpleStateDefine, S, E, C> extends AbstractState { 12 | public SimpleStateDefine(S name) { 13 | super(name); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/support/StateImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state.support; 2 | 3 | import com.github.middleware.fsm.builder.StateMachine; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/7 9 | */ 10 | public class StateImpl, S, E, C> extends AbstractState { 11 | 12 | public StateImpl(S name) { 13 | super(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/builder/state/support/visit/ProxyStateDefine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.state.support.visit; 2 | 3 | import com.github.middleware.fsm.builder.state.StateDefine; 4 | import com.github.middleware.fsm.builder.machine.support.visit.StateMachineProxy; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/7 10 | */ 11 | public interface ProxyStateDefine extends StateDefine { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/annotation/State.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.annotation; 2 | 3 | 4 | import java.lang.annotation.*; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/2/28 10 | */ 11 | @Documented 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target(ElementType.TYPE) 14 | public @interface State { 15 | //计划支持# 16 | String parent() default ""; 17 | 18 | String name(); 19 | 20 | String alias() default ""; 21 | 22 | String entryMethod() default ""; 23 | 24 | String exitMethod() default ""; 25 | 26 | boolean isInitial() default false; 27 | 28 | boolean isEnd() default false; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/annotation/StateMachineParameters.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 状态机的参数(针对ProxyStateMachine类型纠正) 7 | * 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/2/28 11 | */ 12 | @Documented 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.TYPE) 15 | public @interface StateMachineParameters { 16 | Class stateType(); 17 | 18 | Class eventType(); 19 | 20 | Class contextType(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/annotation/States.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.annotation; 2 | 3 | 4 | import java.lang.annotation.*; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/2/28 10 | */ 11 | @Documented 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target(ElementType.TYPE) 14 | public @interface States { 15 | State[] value(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/annotation/Transition.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.annotation; 2 | 3 | import com.github.middleware.fsm.filter.validator.PreChecker; 4 | import com.github.middleware.fsm.filter.validator.support.PreCheckers; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/2/28 12 | */ 13 | @Documented 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target(ElementType.TYPE) 16 | public @interface Transition { 17 | //支持* 18 | String from(); 19 | //支持* 20 | String to(); 21 | //支持* 22 | String on(); 23 | 24 | //when prechecker 25 | Class whenPreChecker() default PreCheckers.Always.class; 26 | //when mvel 与上面二选一 27 | String whenMVEL() default ""; 28 | 29 | boolean isTargetEnd() default false; 30 | 31 | String complete() default ""; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/annotation/Transitions.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/2/28 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.TYPE) 13 | public @interface Transitions { 14 | Transition[] value(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/application/AbstractConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.application; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/6 9 | */ 10 | public abstract class AbstractConfig implements Serializable { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/application/StateMachineConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.application; 2 | 3 | import com.github.middleware.fsm.core.Singletonable; 4 | import com.github.middleware.fsm.core.utils.IDProvider; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/6 10 | */ 11 | public final class StateMachineConfig extends AbstractConfig implements Singletonable { 12 | /** 13 | * 是否开启事件监听 14 | */ 15 | private boolean enableEventListener = true; 16 | private IDProvider idProvider = IDProvider.Default.getInstance(); 17 | 18 | public IDProvider getIdentifier() { 19 | return idProvider; 20 | } 21 | 22 | public StateMachineConfig setIdentifier(IDProvider idProvider) { 23 | this.idProvider = idProvider; 24 | return this; 25 | } 26 | 27 | public boolean enableEventListener() { 28 | return enableEventListener; 29 | } 30 | 31 | public StateMachineConfig setEnableEventListener(boolean enableEventListener) { 32 | this.enableEventListener = enableEventListener; 33 | return this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/loader/AnnotationResovler.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.loader; 2 | 3 | import com.github.middleware.fsm.builder.event.dto.ListenerMappingContext; 4 | import com.github.middleware.fsm.builder.plugin.PluginProvider; 5 | import com.github.middleware.fsm.config.annotation.State; 6 | import com.github.middleware.fsm.config.annotation.Transition; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/3/6 14 | */ 15 | public interface AnnotationResovler { 16 | 17 | List processStateLoader(Class stateMachineClz); 18 | 19 | List processTransitionLoader(Class stateMachineClz); 20 | 21 | ListenerMappingContext processEventListener(PluginProvider providerListener); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/loader/support/AntrlStateLoader.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.loader.support; 2 | 3 | 4 | /** 5 | * @author alex.chen 6 | * @version 1.0.0 7 | * @date 2017/3/1 8 | */ 9 | @Deprecated 10 | public class AntrlStateLoader { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/config/loader/support/XmlStateLoader.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.config.loader.support; 2 | 3 | 4 | /** 5 | * @author alex.chen 6 | * @version 1.0.0 7 | * @date 2017/2/27 8 | */ 9 | @Deprecated 10 | public class XmlStateLoader{ 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/Singletonable.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core; 2 | 3 | /** 4 | * 实现类尽可能在全局内保存单例 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/3 9 | */ 10 | public interface Singletonable { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/Version.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 定位:状态扭转的版本化 7 | * TODO:再定 8 | * 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/1 12 | */ 13 | @Deprecated 14 | @Documented 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.TYPE) 17 | public @interface Version { 18 | String version() default ""; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/convert/Converter.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.convert; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/3/3 7 | */ 8 | public interface Converter { 9 | String objToString(T obj); 10 | 11 | T stringToObj(String name); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/convert/ConverterProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.convert; 2 | 3 | import com.github.middleware.fsm.core.factory.DependProvider; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/7 9 | */ 10 | public interface ConverterProvider { 11 | static ConverterProvider INSTANCE = DependProvider.getInstance().newInstance(ConverterProvider.class); 12 | void register(Class clazz, Converter converter); 13 | void register(Class clazz, Class> converterClass); 14 | void clear(); 15 | Converter getConverter(Class clazz); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/convert/PayloadParse.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.convert; 2 | 3 | import com.github.middleware.fsm.builder.machine.dto.RequestPayload; 4 | 5 | import java.util.Optional; 6 | 7 | /** 8 | * 适用于:PreChecker,Action 9 | * 此处暂时使用反模式,目的提高可重用性及泛型的繁琐性 10 | * 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/2/27 14 | */ 15 | @Deprecated 16 | public interface PayloadParse { 17 | default Optional parse(RequestPayload requestPayload) { 18 | if (requestPayload == null) { 19 | return Optional.empty(); 20 | } 21 | return Optional.of((R) requestPayload); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/convert/support/ConverterImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.convert.support; 2 | 3 | import com.github.middleware.fsm.core.convert.Converter; 4 | import com.github.middleware.fsm.exception.StateMachineException; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import static com.sun.corba.se.spi.activation.IIOP_CLEAR_TEXT.value; 8 | 9 | /** 10 | * S,E 赞只支持String,Enum 11 | * 12 | * @author alex.chen 13 | * @version 1.0.0 14 | * @date 2017/3/7 15 | */ 16 | public class ConverterImpl implements Converter { 17 | private Class type; 18 | 19 | public ConverterImpl(Class type) { 20 | this.type = type; 21 | } 22 | 23 | @Override 24 | public String objToString(T obj) { 25 | if (Enum.class.isAssignableFrom(type)) { 26 | return ((Enum) obj).name(); 27 | } 28 | return obj != null ? obj.toString() : StringUtils.EMPTY; 29 | } 30 | 31 | @Override 32 | public T stringToObj(String name) { 33 | try { 34 | if (String.class.equals(type)) { 35 | return type.cast(value); 36 | } 37 | if (Enum.class.isAssignableFrom(type)) { 38 | return (T) type.cast(Enum.valueOf((Class) type, name)); 39 | } 40 | } catch (Exception ex) { 41 | throw new StateMachineException("类型转换异常: " + type.getName() + " : " + name); 42 | } 43 | throw new StateMachineException("未知类型转换异常: " + type.getName() + " : " + name); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/convert/support/ConverterProviderImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.convert.support; 2 | 3 | import com.github.middleware.fsm.core.convert.ConverterProvider; 4 | import com.google.common.collect.Maps; 5 | import com.github.middleware.fsm.core.convert.Converter; 6 | import com.github.middleware.fsm.core.factory.DependProvider; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/3/7 14 | */ 15 | public class ConverterProviderImpl implements ConverterProvider { 16 | private Map, Converter> converters = Maps.newHashMap(); 17 | @Override 18 | public void register(Class clazz, Converter converter) { 19 | converters.put(clazz, converter); 20 | } 21 | 22 | @Override 23 | public void register(Class clazz, Class> converterClass) { 24 | Converter converter = DependProvider.getInstance().newInstance(converterClass); 25 | register(clazz, converter); 26 | } 27 | 28 | @Override 29 | public void clear() { 30 | converters.clear(); 31 | } 32 | 33 | @Override 34 | public Converter getConverter(Class clazz) { 35 | Converter converter = (Converter)converters.get(clazz); 36 | if(converter==null) { 37 | converter = new ConverterImpl(clazz); 38 | } 39 | return converter; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/el/Dsl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.el; 2 | 3 | /** 4 | * 简化state、transition的操作 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/2/27 9 | */ 10 | public interface Dsl { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/el/MvelScriptManager.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.el; 2 | 3 | /** 4 | * Created by YT on 2017/3/7. 5 | */ 6 | public interface MvelScriptManager { 7 | public static final String SEPARATOR_CHARS = "::"; 8 | public static final String VAR_CONTEXT = "context"; 9 | 10 | T eval(String script, Object context, Class returnType); 11 | 12 | void compile(String script); 13 | 14 | boolean evalBoolean(String script, Object context); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/el/support/MvelScriptManagerImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.el.support; 2 | 3 | import com.github.middleware.fsm.core.el.MvelScriptManager; 4 | import org.mvel2.MVEL; 5 | import org.mvel2.optimizers.OptimizerFactory; 6 | 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/3/9 14 | */ 15 | public class MvelScriptManagerImpl implements MvelScriptManager { 16 | 17 | private Map expressions; 18 | public MvelScriptManagerImpl(){ 19 | OptimizerFactory.setDefaultOptimizer("reflective"); 20 | } 21 | @Override 22 | public T eval(String script, Object context, Class returnType) { 23 | Object evaluateResult = null; 24 | if (getCompiledExpression().containsKey(script)) { 25 | Object exp = getCompiledExpression().get(script); 26 | evaluateResult = MVEL.executeExpression(exp, context); 27 | } else { 28 | evaluateResult = MVEL.eval(script, context); 29 | } 30 | return returnType.cast(evaluateResult); 31 | } 32 | 33 | @Override 34 | public void compile(String script) { 35 | if (!getCompiledExpression().containsKey(script)) { 36 | Object compiled = MVEL.compileExpression(script); 37 | if (compiled != null) { 38 | getCompiledExpression().put(script, compiled); 39 | } 40 | } 41 | } 42 | 43 | private Map getCompiledExpression() { 44 | if (expressions == null) 45 | expressions = new ConcurrentHashMap(); 46 | return expressions; 47 | } 48 | 49 | @Override 50 | public boolean evalBoolean(String script, Object context) { 51 | return eval(script, context, Boolean.class); 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/extension/SPI.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.extension; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 扩展点接口的标识: 7 | * TODO:拓展啥呢,以后再说 8 | * Created by YT on 2017/3/8. 9 | */ 10 | @Documented 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ElementType.TYPE}) 13 | public @interface SPI { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/factory/DependProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.factory; 2 | 3 | import com.github.middleware.fsm.core.types.TypeReference; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | import com.github.middleware.fsm.core.utils.StringUtil; 6 | import com.github.middleware.fsm.filter.wrapper.PostProcessor; 7 | import com.github.middleware.fsm.filter.wrapper.PostProcessorProvider; 8 | import com.google.common.collect.Maps; 9 | import com.github.middleware.fsm.core.Singletonable; 10 | import com.github.middleware.fsm.exception.StateMachineException; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.lang.reflect.Constructor; 15 | import java.util.HashSet; 16 | import java.util.Map; 17 | 18 | /** 19 | * @author alex.chen 20 | * @version 1.0.0 21 | * @date 2017/3/5 22 | */ 23 | public class DependProvider implements Singletonable { 24 | private static final String IMPL_CLASSNAME_SUFFIX = "Impl"; 25 | private static final Logger LOGGER = LoggerFactory.getLogger(DependProvider.class); 26 | private Map, Class> impls; 27 | private static DependProvider instance; 28 | 29 | private DependProvider() { 30 | impls = Maps.newConcurrentMap(); 31 | } 32 | 33 | public static DependProvider getInstance() { 34 | if (instance == null) { 35 | instance = new DependProvider(); 36 | } 37 | return instance; 38 | } 39 | 40 | private Class getClazz(Class clz) { 41 | Class impl = (Class) impls.get(clz); 42 | return impl; 43 | } 44 | 45 | public void regedit(Class clazz, Class implClzz) { 46 | impls.put(clazz, implClzz); 47 | } 48 | 49 | private void unRegedit(Class clazz) { 50 | impls.remove(clazz); 51 | } 52 | 53 | public void clear() { 54 | impls.clear(); 55 | } 56 | 57 | /** 58 | * 实例化 59 | * 60 | * @param clz 61 | * @param 62 | * @return 63 | */ 64 | public T newInstance(Class clz) { 65 | return newInstance(clz, null, null); 66 | } 67 | 68 | /** 69 | * 实例化泛型引用 70 | * 71 | * @param typeRef 72 | * @param 73 | * @return 74 | */ 75 | public T newInstance(TypeReference typeRef) { 76 | return newInstance(typeRef, null, null); 77 | } 78 | 79 | /** 80 | * 实例化带参 81 | * 82 | * @param typeRef 83 | * @param argTypes 84 | * @param args 85 | * @param 86 | * @return 87 | */ 88 | public T newInstance(TypeReference typeRef, Class[] argTypes, Object[] args) { 89 | Class clz = typeRef.getOrgType(); 90 | return clz.cast(newInstance(clz, argTypes, args)); 91 | } 92 | 93 | /** 94 | * 实例化带参 95 | * 96 | * @param clz 97 | * @param argTypes 98 | * @param args 99 | * @param 100 | * @return 101 | */ 102 | public T newInstance(Class clz, Class[] argTypes, Object[] args) { 103 | Class implementationClass = loadImplClazz(clz); 104 | if (args == null) { 105 | return postProcess(clz, ReflectUtil.newInstance(implementationClass)); 106 | } 107 | Constructor constructor = ReflectUtil.getConstructor(implementationClass, argTypes); 108 | return postProcess(clz, ReflectUtil.newInstance(constructor, args)); 109 | } 110 | 111 | /** 112 | * 后置处理 113 | * 114 | * @param clz 115 | * @param component 116 | * @param 117 | * @return 118 | */ 119 | private T postProcess(Class clz, T component) { 120 | PostProcessor postProcessor = PostProcessorProvider.getInstance().getProcessor(clz); 121 | if (postProcessor != null && component != null) { 122 | postProcessor.postProcess(component); 123 | } 124 | return component; 125 | } 126 | 127 | private Class loadImplClazz(Class clz) { 128 | return loadImplClazz(clz, new HashSet>()); 129 | } 130 | 131 | private Class loadImplClazz(Class clz, HashSet> his) { 132 | if (!his.add(clz)) { 133 | throw new StateMachineException("校验异常:非法循环植入" + clz); 134 | } 135 | if (!clz.isInterface()) { 136 | Class implObj = getClazz(clz); 137 | if (implObj != null && !implObj.isInterface()) { 138 | clz = implObj; 139 | } 140 | return clz; 141 | } 142 | Class implObj = getClazz(clz); 143 | if (implObj == null) { 144 | implObj = loaderClazz(clz); 145 | regedit(clz, implObj); 146 | } 147 | return loadImplClazz(implObj, his); 148 | } 149 | 150 | private Class loaderClazz(Class clz) { 151 | Class implObj = null; 152 | String implClazzName = String.format("%s.support.%s%s", StringUtil.getNameByClassName(clz.getName()), clz.getSimpleName(), IMPL_CLASSNAME_SUFFIX); 153 | try { 154 | implObj = Class.forName(implClazzName); 155 | } catch (ClassNotFoundException ex) { 156 | LOGGER.error("执行Class.forName异常:", ex); 157 | implObj = ReflectUtil.getClass(implClazzName); 158 | } 159 | return (Class) implObj; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/factory/SingletonProviderFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.factory; 2 | 3 | import com.google.common.base.Preconditions; 4 | import com.github.middleware.fsm.core.Singletonable; 5 | 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/8 13 | */ 14 | public class SingletonProviderFactory implements Singletonable { 15 | private Map instanceRegistry = new ConcurrentHashMap(); 16 | private static SingletonProviderFactory instance; 17 | 18 | private SingletonProviderFactory() { 19 | } 20 | 21 | public static SingletonProviderFactory getInstance() { 22 | if (instance == null) { 23 | instance = new SingletonProviderFactory(); 24 | } 25 | return instance; 26 | } 27 | 28 | public void register(Class componentClass, Object instance) { 29 | Preconditions.checkArgument(componentClass.isAssignableFrom(instance.getClass())); 30 | instanceRegistry.put(componentClass.getName(), instance); 31 | } 32 | 33 | public void unregister(Class componentClass) { 34 | instanceRegistry.remove(componentClass.getName()); 35 | } 36 | 37 | public void clearRegistry() { 38 | instanceRegistry.clear(); 39 | } 40 | 41 | public T get(Class componentClass) { 42 | Object instance = instanceRegistry.get(componentClass.getName()); 43 | if (instance == null) { 44 | try { 45 | instance = DependProvider.getInstance().newInstance(componentClass); 46 | } catch (Exception e) { 47 | instance = null; 48 | } 49 | if (instance != null) { 50 | register(componentClass, instance); 51 | } 52 | } 53 | return instance != null ? componentClass.cast(instance) : null; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/factory/ThreadExecutorService.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.factory; 2 | 3 | import com.google.common.util.concurrent.MoreExecutors; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * 使用线程池 11 | * 场景:事件监听触发、执行Action 12 | * 13 | * @author alex.chen 14 | * @version 1.0.0 15 | * @date 2017/3/8 16 | */ 17 | public class ThreadExecutorService { 18 | public static ExecutorService getExecutor() { 19 | ExecutorService executorService = SingletonProviderFactory.getInstance().get(ExecutorService.class); 20 | if (executorService == null) { 21 | executorService = registerNewExecutorService(1, 120, TimeUnit.SECONDS); 22 | } 23 | return executorService; 24 | } 25 | 26 | private static ExecutorService registerNewExecutorService(final int threadNum, 27 | final long terminationTimeout, final TimeUnit timeUnit) { 28 | ExecutorService executorService = Executors.newFixedThreadPool(threadNum); 29 | MoreExecutors.addDelayedShutdownHook(executorService, terminationTimeout, timeUnit); 30 | SingletonProviderFactory.getInstance().register(ExecutorService.class, executorService); 31 | return executorService; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/types/ProcessingQueue.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.types; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Queue; 9 | import java.util.concurrent.ArrayBlockingQueue; 10 | 11 | /** 12 | * 13 | * @author alex.chen 14 | * @version 1.0.0 15 | * @date 2017/2/28 16 | */ 17 | public class ProcessingQueue { 18 | private static final Logger LOGGER = LoggerFactory.getLogger(ProcessingQueue.class); 19 | public static final int MAX_EVENT_QUEUE_SIZE = 30; 20 | private Queue eventQueue = new ArrayBlockingQueue(MAX_EVENT_QUEUE_SIZE); 21 | //全局事件 22 | private List globalEvents = new ArrayList(); 23 | private E currentEvent; 24 | 25 | /** 26 | * add event to queue 27 | * 28 | * @param newEvent 29 | */ 30 | public void addEvent(E newEvent) { 31 | if (newEvent == null) 32 | return; 33 | eventQueue.offer(newEvent); 34 | } 35 | 36 | /** 37 | * get a event 38 | * 39 | * @return 40 | */ 41 | public E nextEvent() { 42 | currentEvent = eventQueue.poll(); 43 | return currentEvent; 44 | } 45 | 46 | /** 47 | * @param resultEvent 48 | */ 49 | @Deprecated 50 | public void addGlobalEvent(E resultEvent) { 51 | if (resultEvent != null) { 52 | globalEvents.add(resultEvent); 53 | if (LOGGER.isDebugEnabled()) { 54 | LOGGER.debug("addGlobalEvent(" + resultEvent + ")"); 55 | } 56 | } 57 | } 58 | 59 | public E currentEvent() { 60 | return currentEvent; 61 | } 62 | 63 | public List getGlobalEvents() { 64 | return this.globalEvents; 65 | } 66 | 67 | @Deprecated 68 | public void clearGlobalEvents() { 69 | globalEvents.clear(); 70 | } 71 | 72 | public boolean hasEvent() { 73 | return eventQueue.size() > 0; 74 | } 75 | 76 | public boolean hasGlobalEvents() { 77 | return !globalEvents.isEmpty(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/types/TypeReference.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.types; 2 | 3 | import com.github.middleware.fsm.exception.StateMachineException; 4 | 5 | import java.lang.reflect.*; 6 | 7 | /** 8 | * 处理Super Type Tokens 9 | * 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/6 13 | */ 14 | public abstract class TypeReference { 15 | private Type type; 16 | 17 | protected TypeReference() { 18 | type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 19 | } 20 | 21 | public Type getType() { 22 | return type; 23 | } 24 | 25 | public final Class getOrgType() { 26 | // raw type is |T| 27 | Class result = (Class) getOrgType(type); 28 | return result; 29 | } 30 | 31 | static Class getOrgType(Type type) { 32 | if (type instanceof Class) { 33 | return (Class) type; 34 | } else if (type instanceof ParameterizedType) { 35 | ParameterizedType parameterizedType = (ParameterizedType) type; 36 | // JDK implementation declares getRawType() to return Class 37 | return (Class) parameterizedType.getRawType(); 38 | } else if (type instanceof GenericArrayType) { 39 | GenericArrayType genericArrayType = (GenericArrayType) type; 40 | return Array.newInstance(getOrgType(genericArrayType.getGenericComponentType()), 0).getClass(); 41 | } else if (type instanceof TypeVariable) { 42 | // First bound is always the "primary" bound that determines the 43 | // runtime signature. 44 | return getOrgType(((TypeVariable) type).getBounds()[0]); 45 | } else if (type instanceof WildcardType) { 46 | // Wildcard can have one and only one upper bound. 47 | return getOrgType(((WildcardType) type).getUpperBounds()[0]); 48 | } else { 49 | throw new StateMachineException(type + " unsupported"); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/utils/IDProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.utils; 2 | 3 | import com.github.middleware.fsm.core.Singletonable; 4 | import org.apache.commons.lang3.RandomStringUtils; 5 | 6 | import java.util.UUID; 7 | 8 | /** 9 | * @author alex.chen 10 | * @version 1.0.0 11 | * @date 2017/3/6 12 | */ 13 | public interface IDProvider { 14 | String ID_FORMAT_PREFIX = "fsm-%s"; 15 | 16 | String get(); 17 | 18 | final class Default implements IDProvider, Singletonable { 19 | private static IDProvider instance; 20 | 21 | private Default() { 22 | } 23 | 24 | public static IDProvider getInstance() { 25 | if (instance == null) { 26 | instance = new Default(); 27 | } 28 | return instance; 29 | } 30 | 31 | @Override 32 | public String get() { 33 | return String.format(ID_FORMAT_PREFIX, RandomStringUtils.randomAlphanumeric(12)); 34 | } 35 | } 36 | 37 | final class UUIDProvider implements IDProvider, Singletonable { 38 | private static IDProvider instance; 39 | 40 | public static IDProvider getInstance() { 41 | if (instance == null) { 42 | instance = new UUIDProvider(); 43 | } 44 | return instance; 45 | } 46 | 47 | @Override 48 | public String get() { 49 | return String.format(ID_FORMAT_PREFIX, UUID.randomUUID().toString().replace("-", "")); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/utils/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.utils; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | /** 6 | * Created by fei.chen on 2017/9/11. 7 | */ 8 | public class JsonUtil { 9 | 10 | public static String json(Object input) { 11 | try { 12 | return JSON.toJSONString(input); 13 | } catch (Throwable ex) { 14 | return ex.getMessage(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/utils/Precondition.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.utils; 2 | 3 | import com.github.middleware.fsm.exception.StateMachineException; 4 | 5 | /** 6 | * 来源于guava 7 | * 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/3/10 11 | */ 12 | public final class Precondition { 13 | public static void checkArgument(boolean expression, Object errorMessage) { 14 | if (!expression) { 15 | throw new StateMachineException(String.valueOf(errorMessage)); 16 | } 17 | } 18 | 19 | public static void checkState(boolean expression, Object errorMessage) { 20 | if (!expression) { 21 | throw new StateMachineException(String.valueOf(errorMessage)); 22 | } 23 | } 24 | 25 | public static T checkNotNull(T reference, Object errorMessage) { 26 | if (reference == null) { 27 | throw new StateMachineException(String.valueOf(errorMessage)); 28 | } else { 29 | return reference; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/core/utils/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.utils; 2 | 3 | import com.github.middleware.fsm.exception.StateMachineException; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/7 9 | */ 10 | public class StringUtil { 11 | /** 12 | * 根据classname截取 13 | * 14 | * @param className 15 | * @return 16 | */ 17 | public static String getNameByClassName(final String className) { 18 | if (className == null || className.length() == 0) 19 | throw new StateMachineException("校验异常:参数不能为空"); 20 | int index = className.lastIndexOf('.'); 21 | if (index != -1) 22 | return className.substring(0, index); 23 | return ""; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/ApiObsoleteException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/3/8 7 | */ 8 | public class ApiObsoleteException extends StateMachineException { 9 | public ApiObsoleteException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * 异常消息清单 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/2/24 9 | */ 10 | public enum ErrorCode { 11 | NOT_ALLOW_ACCESS_FIELD(10002, "wasn't allowed to get field '%s.%s'"), 12 | NOT_ALLOW_ACCESS_METHOD(10004, "wasn't allowed to get method '%s.%s(%s)'"), 13 | METHOD_NOT_FOUND(10006, "couldn't find method '%s.%s(%s)'"), 14 | FIELD_NOT_FOUND(10008, "couldn't find field '%s.%s'"), 15 | ILLEGAL_CLASS_NAME(10010, "illegal class name"), 16 | METHOD_INVOKE_ERROR(10012, "couldn't invoke '%s' with %s on %s: %s"); 17 | private int code; 18 | private String description; 19 | 20 | ErrorCode(int code, String description) { 21 | this.code = code; 22 | this.description = description; 23 | } 24 | 25 | public int getCode() { 26 | return code; 27 | } 28 | 29 | public String getDescription() { 30 | return description; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/EventAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * 5 | * @author alex.chen 6 | * @version 1.0.0 7 | * @date 2017/2/27 8 | */ 9 | public class EventAlreadyExistsException extends StateMachineException { 10 | public EventAlreadyExistsException(String errorMessage) { 11 | super(errorMessage); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/EventNotDefinedException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/2/24 7 | */ 8 | public class EventNotDefinedException extends StateMachineException { 9 | public EventNotDefinedException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/IllegalAnnotationException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/2/24 7 | */ 8 | public class IllegalAnnotationException extends StateMachineException{ 9 | public IllegalAnnotationException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/IllegalPreCheckerException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/2/27 7 | */ 8 | public class IllegalPreCheckerException extends StateMachineException { 9 | public IllegalPreCheckerException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/NotPayloadException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/3/8 7 | */ 8 | public class NotPayloadException extends StateMachineException { 9 | public NotPayloadException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/NotSuchEventException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/3/8 7 | */ 8 | public class NotSuchEventException extends StateMachineException{ 9 | public NotSuchEventException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/NotSuchStateException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/2/27 7 | */ 8 | public class NotSuchStateException extends StateMachineException { 9 | public NotSuchStateException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/NotSupportedException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/2/28 7 | */ 8 | public class NotSupportedException extends StateMachineException { 9 | public NotSupportedException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/SateAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/2/24 7 | */ 8 | public class SateAlreadyExistsException extends StateMachineException { 9 | public SateAlreadyExistsException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/StateMachineException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * 异常Base类 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/2/24 9 | */ 10 | public class StateMachineException extends RuntimeException { 11 | private int errorCode; 12 | private String errorMessage; 13 | private Throwable targetException; 14 | 15 | public StateMachineException() { 16 | } 17 | 18 | public StateMachineException(String errorMessage) { 19 | super(errorMessage); 20 | this.errorMessage = errorMessage; 21 | } 22 | 23 | public StateMachineException(ErrorCode errorCode) { 24 | this.errorCode = errorCode.getCode(); 25 | this.errorMessage = String.format("%08d : %s.", getErrorCode(), errorCode.getDescription()); 26 | } 27 | 28 | public StateMachineException(ErrorCode errorCode, Object... parameters) { 29 | this.errorCode = errorCode.getCode(); 30 | this.errorMessage = String.format("%08d : %s.", getErrorCode(), 31 | String.format(errorCode.getDescription(), parameters)); 32 | } 33 | 34 | public StateMachineException(Throwable targetException, ErrorCode errorCode, Object... parameters) { 35 | this(errorCode, parameters); 36 | this.targetException = targetException; 37 | } 38 | 39 | public int getErrorCode() { 40 | return errorCode; 41 | } 42 | 43 | public void setErrorCode(int errorCode) { 44 | this.errorCode = errorCode; 45 | } 46 | 47 | public String getErrorMessage() { 48 | return errorMessage; 49 | } 50 | 51 | public void setErrorMessage(String errorMessage) { 52 | this.errorMessage = errorMessage; 53 | } 54 | 55 | public Throwable getTargetException() { 56 | return targetException; 57 | } 58 | 59 | public void setTargetException(Throwable targetException) { 60 | this.targetException = targetException; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "StateMachineException{" + 66 | "errorCode=" + errorCode + 67 | ", errorMessage='" + errorMessage + '\'' + 68 | ", targetException=" + targetException + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/exception/StateNotDefinedException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.exception; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/2/24 7 | */ 8 | public class StateNotDefinedException extends StateMachineException { 9 | public StateNotDefinedException(String errorMessage) { 10 | super(errorMessage); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/annotation/PostConstruct.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 状态机实例化后预处理标示 7 | * Created by YT on 2017/3/12. 8 | */ 9 | @Documented 10 | @Retention(value = RetentionPolicy.RUNTIME) 11 | @Target(ElementType.METHOD) 12 | public @interface PostConstruct { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/validator/PreChecker.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.validator; 2 | 3 | import com.github.middleware.fsm.exception.StateMachineException; 4 | 5 | /** 6 | * 检查器,在状态扭转链前被执行 7 | * 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/2/27 11 | */ 12 | public interface PreChecker { 13 | boolean validate(C context) throws StateMachineException; 14 | 15 | String getName(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/validator/support/AbstractPreChecker.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.validator.support; 2 | 3 | import com.github.middleware.fsm.filter.validator.PreChecker; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/3 9 | */ 10 | public abstract class AbstractPreChecker implements PreChecker { 11 | @Override 12 | public String getName() { 13 | return getClass().getSimpleName() + "_Checker"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/validator/support/MvelCheckerImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.validator.support; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.github.middleware.fsm.core.el.MvelScriptManager; 5 | import com.github.middleware.fsm.filter.validator.PreChecker; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.Map; 11 | 12 | /** 13 | * @author alex.chen 14 | * @version 1.0.0 15 | * @date 2017/3/7 16 | */ 17 | public class MvelCheckerImpl implements PreChecker { 18 | private static final Logger LOGGER = LoggerFactory.getLogger(MvelCheckerImpl.class); 19 | private String mvelExpr; 20 | private String name; 21 | private MvelScriptManager scriptManager; 22 | private String script; 23 | 24 | public MvelCheckerImpl(String script, MvelScriptManager scriptManager) { 25 | String[] arrays = StringUtils.split(script, MvelScriptManager.SEPARATOR_CHARS); 26 | if (arrays.length == 2) { 27 | this.name = arrays[0].trim(); 28 | this.mvelExpr = arrays[1].trim(); 29 | } else { 30 | this.name = "_NoName_"; 31 | this.mvelExpr = arrays[0].trim(); 32 | } 33 | 34 | this.script = script; 35 | this.scriptManager = scriptManager; 36 | 37 | scriptManager.compile(mvelExpr); 38 | } 39 | 40 | @Override 41 | public boolean validate(C context) { 42 | try { 43 | Map variables = Maps.newHashMap(); 44 | variables.put(MvelScriptManager.VAR_CONTEXT, context); 45 | return scriptManager.evalBoolean(mvelExpr, variables); 46 | } catch (Exception e) { 47 | LOGGER.error("Evaluate \"" + mvelExpr + "\" failed with " + e.getMessage() + (e.getCause() != null ? ", which caused by " + e.getCause().getMessage() : "")); 48 | return false; 49 | } 50 | } 51 | 52 | @Override 53 | public String getName() { 54 | return name; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/validator/support/PreCheckers.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.validator.support; 2 | 3 | import com.github.middleware.fsm.filter.validator.PreChecker; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 验证的常规类 9 | * 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/3 13 | */ 14 | public class PreCheckers { 15 | public static boolean validate(PreChecker checker, C context) { 16 | return checker != null && context != null && checker.validate(context); 17 | } 18 | 19 | public static PreChecker always() { 20 | return new Always(); 21 | } 22 | 23 | public static PreChecker never() { 24 | return new Always(); 25 | } 26 | 27 | public static PreChecker and(final List> checkers) { 28 | return new PreChecker() { 29 | @Override 30 | public boolean validate(C context) { 31 | for (PreChecker condition : checkers) { 32 | if (!condition.validate(context)) { 33 | return false; 34 | } 35 | } 36 | return true; 37 | } 38 | 39 | @Override 40 | public String getName() { 41 | return checkers.stream().map(x -> x.getName()).toArray().toString(); 42 | } 43 | }; 44 | } 45 | 46 | public static PreChecker and(final PreChecker first, final PreChecker second) { 47 | return new PreChecker() { 48 | @Override 49 | public boolean validate(C context) { 50 | return first.validate(context) && second.validate(context); 51 | } 52 | 53 | @Override 54 | public String getName() { 55 | return first.getName() + " and " + second.getName(); 56 | } 57 | }; 58 | } 59 | 60 | public static PreChecker or(final List> checkers) { 61 | return new PreChecker() { 62 | @Override 63 | public boolean validate(C context) { 64 | for (PreChecker condition : checkers) { 65 | if (condition.validate(context)) { 66 | return true; 67 | } 68 | } 69 | return false; 70 | } 71 | 72 | @Override 73 | public String getName() { 74 | return checkers.stream().map(x -> x.getName()).toArray().toString(); 75 | } 76 | }; 77 | } 78 | 79 | public static PreChecker or(final PreChecker first, final PreChecker second) { 80 | return new PreChecker() { 81 | @Override 82 | public boolean validate(C context) { 83 | return first.validate(context) || second.validate(context); 84 | } 85 | 86 | @Override 87 | public String getName() { 88 | return first.getName() + " Or " + second.getName(); 89 | } 90 | }; 91 | } 92 | 93 | public static PreChecker not(final PreChecker condition) { 94 | return new PreChecker() { 95 | @Override 96 | public boolean validate(C context) { 97 | return !condition.validate(context); 98 | } 99 | 100 | @Override 101 | public String getName() { 102 | return "Not" + condition.getName(); 103 | } 104 | }; 105 | } 106 | 107 | 108 | public static class Always extends AbstractPreChecker { 109 | @Override 110 | public boolean validate(C context) { 111 | return true; 112 | } 113 | } 114 | 115 | public static class Never extends AbstractPreChecker { 116 | @Override 117 | public boolean validate(C context) { 118 | return false; 119 | } 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/wrapper/ComposPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.wrapper; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/3/8 7 | */ 8 | public interface ComposPostProcessor extends PostProcessor { 9 | void compose(PostProcessor processor); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/wrapper/PostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.wrapper; 2 | 3 | /** 4 | * 后置处理器 5 | * 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/6 9 | */ 10 | @FunctionalInterface 11 | public interface PostProcessor { 12 | void postProcess(T Obj); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/wrapper/PostProcessorProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.wrapper; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import com.github.middleware.fsm.core.factory.DependProvider; 6 | import com.github.middleware.fsm.core.utils.Precondition; 7 | import com.github.middleware.fsm.filter.wrapper.support.ComposPostProcessorImpl; 8 | 9 | import java.lang.reflect.Method; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * @author alex.chen 15 | * @version 1.0.0 16 | * @date 2017/3/6 17 | */ 18 | public class PostProcessorProvider { 19 | private static PostProcessorProvider instance; 20 | private Map, PostProcessor> process; 21 | private static final String POSTPROCESS_NAME = "postProcess"; 22 | 23 | private PostProcessorProvider() { 24 | process = Maps.newConcurrentMap(); 25 | } 26 | 27 | public static PostProcessorProvider getInstance() { 28 | if (instance == null) { 29 | instance = new PostProcessorProvider(); 30 | } 31 | return instance; 32 | } 33 | 34 | public PostProcessor getProcessor(Class clz) { 35 | return (PostProcessor) process.get(clz); 36 | } 37 | 38 | public List> getProcessors(Class componentClass) { 39 | List> postProcessors = Lists.newArrayList(); 40 | for (Map.Entry, PostProcessor> entry : process.entrySet()) { 41 | if (entry.getKey().isAssignableFrom(componentClass)) { 42 | PostProcessor postProcessor = (PostProcessor) entry.getValue(); 43 | postProcessors.add(postProcessor); 44 | } 45 | } 46 | return postProcessors; 47 | } 48 | 49 | public void register(Class componentClass, Class> postProcessorClass) { 50 | PostProcessor postProcessor = DependProvider.getInstance().newInstance(postProcessorClass); 51 | register(componentClass, postProcessor); 52 | } 53 | 54 | public void register(Class clazz, PostProcessor postProcessor) { 55 | Method method = getOneMethod(postProcessor.getClass(), POSTPROCESS_NAME); 56 | Class[] params = method.getParameterTypes(); 57 | Precondition.checkArgument(params.length == 1, "校验异常:参数类型匹配不正确!"); 58 | Precondition.checkArgument(params[0].isAssignableFrom(clazz), "校验异常:参数类型匹配不正确!"); 59 | 60 | if (process.containsKey(clazz)) { 61 | PostProcessor existProcessor = (PostProcessor) process.get(clazz); 62 | if (existProcessor instanceof ComposPostProcessorImpl) { 63 | ((ComposPostProcessorImpl) existProcessor).compose(postProcessor); 64 | } else {//合并 65 | process.remove(clazz); 66 | ComposPostProcessorImpl compositeProcessor = new ComposPostProcessorImpl(existProcessor); 67 | compositeProcessor.compose(postProcessor); 68 | process.put(clazz, compositeProcessor); 69 | } 70 | } else { 71 | process.put(clazz, postProcessor); 72 | } 73 | } 74 | 75 | public void unRegister(Class componentClass) { 76 | process.remove(componentClass); 77 | } 78 | 79 | private Method getOneMethod(Class clazz, String name) { 80 | for (Method m : clazz.getMethods()) 81 | if (m.getName().equals(name)) { 82 | return m; 83 | } 84 | return null; 85 | } 86 | 87 | public void clear() { 88 | process.clear(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/wrapper/support/ComposPostProcessorImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.wrapper.support; 2 | 3 | import com.github.middleware.fsm.filter.wrapper.ComposPostProcessor; 4 | import com.google.common.collect.Lists; 5 | import com.github.middleware.fsm.filter.wrapper.PostProcessor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/7 13 | */ 14 | public class ComposPostProcessorImpl implements ComposPostProcessor { 15 | private List> processors; 16 | 17 | public ComposPostProcessorImpl() { 18 | this(null); 19 | } 20 | 21 | public ComposPostProcessorImpl(PostProcessor processors) { 22 | this.processors = Lists.newArrayList(processors); 23 | } 24 | 25 | @Override 26 | public void compose(PostProcessor processor) { 27 | if (!processors.contains(processor)) { 28 | processors.add(processor); 29 | } 30 | } 31 | 32 | @Override 33 | public void postProcess(T Obj) { 34 | for (PostProcessor processor : processors) { 35 | processor.postProcess(Obj); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/filter/wrapper/support/PostConstructPostProcessorImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter.wrapper.support; 2 | 3 | import com.github.middleware.fsm.filter.annotation.PostConstruct; 4 | import com.github.middleware.fsm.core.utils.ReflectUtil; 5 | import com.github.middleware.fsm.filter.wrapper.PostProcessor; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * 后置处理器() 11 | * @author alex.chen 12 | * @version 1.0.0 13 | * @date 2017/3/8 14 | */ 15 | public class PostConstructPostProcessorImpl implements PostProcessor { 16 | @Override 17 | public void postProcess(final Object component) { 18 | Class componentClass = component.getClass(); 19 | ReflectUtil.doWithMethods(componentClass, new ReflectUtil.MethodFilter() { 20 | @Override 21 | public boolean matches(Method method) { 22 | return ReflectUtil.isAnnotatedWith(method, PostConstruct.class) && 23 | (method.getParameterTypes() == null || method.getParameterTypes().length == 0); 24 | } 25 | }, new ReflectUtil.MethodCallback() { 26 | @Override 27 | public void doWith(Method method) { 28 | ReflectUtil.invoke(method, component); 29 | } 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/spring/StatemachineBuilderSupport.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.spring; 2 | 3 | /** 4 | * Created by netuser on 17-6-5. 5 | */ 6 | @Deprecated 7 | public class StatemachineBuilderSupport { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/spring/StatemachineFactoryBean.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.spring; 2 | 3 | import com.github.middleware.fsm.builder.machine.factroy.StateMachineBuilderFactory; 4 | import com.github.middleware.fsm.builder.machine.support.visit.AbstractStateMachineProxy; 5 | import com.github.middleware.fsm.builder.machine.support.visit.StateMachineBuilderProxy; 6 | import com.github.middleware.fsm.filter.wrapper.PostProcessor; 7 | import com.github.middleware.fsm.filter.wrapper.PostProcessorProvider; 8 | import org.springframework.beans.factory.FactoryBean; 9 | import org.springframework.beans.factory.InitializingBean; 10 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory; 11 | import org.springframework.context.ApplicationContext; 12 | import org.springframework.util.Assert; 13 | 14 | /** 15 | * Created by netuser on 17-6-5. 16 | */ 17 | public class StatemachineFactoryBean implements InitializingBean, FactoryBean { 18 | private Class statemachineImplClz; 19 | private ApplicationContext applicationContext; 20 | 21 | @Override 22 | public T getObject() throws Exception { 23 | if (AbstractStateMachineProxy.class.isAssignableFrom(statemachineImplClz)) { 24 | System.out.println(); 25 | StateMachineBuilderProxy builderProxy = StateMachineBuilderFactory.create(statemachineImplClz); 26 | //builderProxy.newPluginBuilder(new FsmListenerLogger()).install(); 27 | PostProcessor postProcessor = new PostProcessor() { 28 | @Override 29 | public void postProcess(T obj) { 30 | AutowireCapableBeanFactory capableBeanFactory = applicationContext.getAutowireCapableBeanFactory(); 31 | capableBeanFactory.autowireBean(obj); 32 | } 33 | }; 34 | PostProcessorProvider.getInstance().register(statemachineImplClz, postProcessor); 35 | return (T) builderProxy.newStateMachine(); 36 | } 37 | throw new Exception("no such statemachineFactoryBean."); 38 | } 39 | 40 | @Override 41 | public Class getObjectType() { 42 | return statemachineImplClz; 43 | } 44 | 45 | @Override 46 | public boolean isSingleton() { 47 | return true; 48 | } 49 | 50 | @Override 51 | public void afterPropertiesSet() throws Exception { 52 | Assert.notNull(this.statemachineImplClz, "Property statemachineImplClz is required."); 53 | Assert.notNull(this.applicationContext, "Property applicationContext is required."); 54 | } 55 | 56 | public Class getStatemachineImplClz() { 57 | return statemachineImplClz; 58 | } 59 | 60 | public void setStatemachineImplClz(Class statemachineImplClz) { 61 | this.statemachineImplClz = statemachineImplClz; 62 | } 63 | 64 | public ApplicationContext getApplicationContext() { 65 | return applicationContext; 66 | } 67 | 68 | public void setApplicationContext(ApplicationContext applicationContext) { 69 | this.applicationContext = applicationContext; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/spring/StatemachineScannerConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.spring; 2 | 3 | import com.github.middleware.fsm.spring.annotation.StatemachineService; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.BeansException; 7 | import org.springframework.beans.factory.InitializingBean; 8 | import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; 9 | import org.springframework.beans.factory.config.BeanDefinitionHolder; 10 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 11 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 12 | import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; 13 | import org.springframework.beans.factory.support.GenericBeanDefinition; 14 | import org.springframework.context.ApplicationContext; 15 | import org.springframework.context.ApplicationContextAware; 16 | import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; 17 | import org.springframework.core.type.filter.AnnotationTypeFilter; 18 | import org.springframework.util.Assert; 19 | 20 | import java.lang.annotation.Annotation; 21 | import java.util.Iterator; 22 | import java.util.Set; 23 | 24 | /** 25 | * Created by netuser on 17-6-5. 26 | */ 27 | public class StatemachineScannerConfigurer implements InitializingBean, ApplicationContextAware, BeanDefinitionRegistryPostProcessor { 28 | private static final Logger LOG = LoggerFactory.getLogger(StatemachineScannerConfigurer.class); 29 | private ApplicationContext applicationContext; 30 | private String basePackages; 31 | private Class annotationClz = StatemachineService.class; 32 | 33 | public String getBasePackages() { 34 | return basePackages; 35 | } 36 | 37 | public void setBasePackages(String basePackages) { 38 | this.basePackages = basePackages; 39 | } 40 | 41 | public Class getAnnotationClz() { 42 | return annotationClz; 43 | } 44 | 45 | public void setAnnotationClz(Class annotationClz) { 46 | this.annotationClz = annotationClz; 47 | } 48 | 49 | @Override 50 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 51 | this.applicationContext = applicationContext; 52 | } 53 | 54 | @Override 55 | public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { 56 | Scanner scanner = new Scanner(beanDefinitionRegistry); 57 | scanner.setResourceLoader(this.applicationContext); 58 | scanner.scan(this.basePackages); 59 | } 60 | 61 | @Override 62 | public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { 63 | } 64 | 65 | @Override 66 | public void afterPropertiesSet() throws Exception { 67 | Assert.hasLength(this.basePackages, "Property basePackages is not empty."); 68 | Assert.notNull(this.annotationClz, "Property annotationClz is required."); 69 | Assert.notNull(this.applicationContext, "Property applicationContext is required."); 70 | } 71 | 72 | private final class Scanner extends ClassPathBeanDefinitionScanner { 73 | public Scanner(BeanDefinitionRegistry registry) { 74 | super(registry); 75 | } 76 | 77 | @Override 78 | protected void registerDefaultFilters() { 79 | this.addIncludeFilter(new AnnotationTypeFilter(getAnnotationClz())); 80 | } 81 | 82 | @Override 83 | protected Set doScan(String... basePackages) { 84 | Set beanDefinitionHolders = super.doScan(basePackages); 85 | if (beanDefinitionHolders.isEmpty()) { 86 | LOG.warn("statemachine class not found in " + basePackages); 87 | } else { 88 | Iterator items = beanDefinitionHolders.iterator(); 89 | while (items.hasNext()) { 90 | BeanDefinitionHolder beanHolder = items.next(); 91 | GenericBeanDefinition genericBean = (GenericBeanDefinition) beanHolder.getBeanDefinition(); 92 | genericBean.getPropertyValues().addPropertyValue("statemachineImplClz", genericBean.getBeanClassName()); 93 | genericBean.getPropertyValues().addPropertyValue("applicationContext", StatemachineScannerConfigurer.this.applicationContext); 94 | genericBean.setBeanClass(StatemachineFactoryBean.class); 95 | } 96 | } 97 | return beanDefinitionHolders; 98 | } 99 | 100 | @Override 101 | protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { 102 | return super.isCandidateComponent(beanDefinition) && beanDefinition.getMetadata().hasAnnotation(getAnnotationClz().getName()); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/github/middleware/fsm/spring/annotation/StatemachineService.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.spring.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * Created by netuser on 17-6-5. 7 | */ 8 | @Documented 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.TYPE) 11 | public @interface StatemachineService { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/images/thread.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex2chen/j-statemachine/741c14a0346c6bb0bce639e22717ce29c65bd548/src/main/resources/images/thread.jpg -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L: %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/builder/AnnotationResovler_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder; 2 | 3 | import com.github.middleware.fsm.builder.event.annotation.OnAfterAction; 4 | import com.github.middleware.fsm.builder.event.annotation.OnTransitionBegin; 5 | import com.github.middleware.fsm.builder.event.dto.ListenerMappingContext; 6 | import com.github.middleware.fsm.builder.exec.Action; 7 | import com.github.middleware.fsm.config.annotation.State; 8 | import com.github.middleware.fsm.config.annotation.Transition; 9 | import com.github.middleware.fsm.config.annotation.Transitions; 10 | import com.github.middleware.fsm.config.loader.AnnotationResovler; 11 | import com.github.middleware.fsm.core.factory.DependProvider; 12 | import com.github.middleware.fsm.builder.plugin.support.AbstractPluginProvider; 13 | import org.junit.Assert; 14 | import org.junit.Test; 15 | 16 | import java.util.List; 17 | 18 | import static org.hamcrest.core.Is.is; 19 | 20 | /** 21 | * @author alex.chen 22 | * @version 1.0.0 23 | * @date 2017/3/17 24 | */ 25 | @State(name = "Test", alias = "_test") 26 | @Transitions({@Transition(from = "SH", to = "BJ", on = "火车"), @Transition(from = "BJ", to = "WH", on = "飞机")}) 27 | public class AnnotationResovler_test { 28 | private AnnotationResovler annotationResovler = DependProvider.getInstance().newInstance(AnnotationResovler.class); 29 | 30 | @Test 31 | public void go_processStateLoader() { 32 | List states = annotationResovler.processStateLoader(AnnotationResovler_test.class); 33 | Assert.assertThat(states.size(), is(1)); 34 | } 35 | 36 | @Test 37 | public void go_processTransitionLoader() { 38 | List transitions = annotationResovler.processTransitionLoader(AnnotationResovler_test.class); 39 | System.out.println(transitions); 40 | Assert.assertThat(transitions.size(), is(2)); 41 | } 42 | 43 | @Test 44 | public void go_processEventListener() { 45 | ListenerMappingContext listenerMappingContext = annotationResovler.processEventListener(new MonitorPlugin()); 46 | System.out.println(listenerMappingContext); 47 | Assert.assertThat(listenerMappingContext.getMappingContextItems().size(), is(2)); 48 | } 49 | 50 | public class MonitorPlugin extends AbstractPluginProvider { 51 | @OnTransitionBegin(when = "1==1") 52 | public void onTransB(Object from, Object event, Object context) { 53 | 54 | } 55 | 56 | @OnAfterAction 57 | public void onExexAfter(Object sourceState, Object targetState, 58 | Object event, Object context, int[] mOfN, Action action) { 59 | 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/builder/Performance_Test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @author alex.chen 7 | * @version 1.0.0 8 | * @date 2017/3/12 9 | */ 10 | public class Performance_Test { 11 | @Test 12 | public void go_test() { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/builder/dto/Order.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.builder.dto; 2 | 3 | import java.io.Serializable; 4 | import java.math.BigDecimal; 5 | 6 | /** 7 | * @author alex.chen 8 | * @version 1.0.0 9 | * @date 2017/3/13 10 | */ 11 | public class Order implements Serializable { 12 | private int id; 13 | private String name; 14 | private BigDecimal price; 15 | 16 | public Order() { 17 | } 18 | 19 | public Order(int id, String name, BigDecimal price) { 20 | this.id = id; 21 | this.name = name; 22 | this.price = price; 23 | } 24 | 25 | public int getId() { 26 | return id; 27 | } 28 | 29 | public void setId(int id) { 30 | this.id = id; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public void setName(String name) { 38 | this.name = name; 39 | } 40 | 41 | public BigDecimal getPrice() { 42 | return price; 43 | } 44 | 45 | public void setPrice(BigDecimal price) { 46 | this.price = price; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/client/QuickStartV2_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.client; 2 | 3 | import com.github.middleware.fsm.builder.dto.Order; 4 | import com.github.middleware.fsm.client.constants.OrderEvent; 5 | import com.github.middleware.fsm.client.constants.OrderState; 6 | import com.github.middleware.fsm.client.v2.OrderStateMachineV2; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 13 | 14 | import java.math.BigDecimal; 15 | 16 | /** 17 | * Created by netuser on 17-6-6. 18 | */ 19 | @ContextConfiguration("classpath*:spring-statemachine.xml") 20 | @RunWith(SpringJUnit4ClassRunner.class) 21 | public class QuickStartV2_test { 22 | @Autowired 23 | private OrderStateMachineV2 orderStateMachine; 24 | 25 | @Test 26 | public void go_handleEvent() { 27 | Order order = new Order() {{ 28 | setId(1); 29 | setName("xiaomi5"); 30 | setPrice(new BigDecimal(1)); 31 | //setPrice(new BigDecimal(100000)); 32 | }}; 33 | orderStateMachine.handleEvent(OrderEvent.ATA1, order); 34 | Assert.assertTrue(orderStateMachine.getCurrentState() == OrderState.A1); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/client/constants/OrderEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.client.constants; 2 | 3 | /** 4 | * Created by netuser on 17-6-6. 5 | */ 6 | public enum OrderEvent { 7 | ATA1, A1TA2, A2TA3, A3TA4 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/client/constants/OrderState.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.client.constants; 2 | 3 | /** 4 | * Created by netuser on 17-6-6. 5 | */ 6 | public enum OrderState { 7 | A, A1, A2, A3, A4, A4a, A5, A5a, A5b 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/client/v2/OrderStateMachineImplV2.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.client.v2; 2 | 3 | import com.github.middleware.fsm.builder.dto.Order; 4 | import com.github.middleware.fsm.client.constants.OrderEvent; 5 | import com.github.middleware.fsm.client.constants.OrderState; 6 | import com.github.middleware.fsm.spring.annotation.StatemachineService; 7 | import com.github.middleware.fsm.builder.machine.support.visit.AbstractStateMachineProxy; 8 | import com.github.middleware.fsm.builder.plugin.log.LogExec; 9 | 10 | /** 11 | * Created by netuser on 17-6-6. 12 | */ 13 | @StatemachineService 14 | public class OrderStateMachineImplV2 extends AbstractStateMachineProxy implements OrderStateMachineV2 { 15 | private String name; 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public void setName(String name) { 22 | this.name = name; 23 | } 24 | 25 | @LogExec 26 | @Override 27 | public void enterA1(OrderState from, OrderState to, OrderEvent event, Order context) { 28 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 29 | } 30 | 31 | @Override 32 | public void enterA2(OrderState from, OrderState to, OrderEvent event, Order context) { 33 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 34 | } 35 | 36 | @Override 37 | public void enterA3(OrderState from, OrderState to, OrderEvent event, Order context) { 38 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 39 | } 40 | 41 | @Override 42 | public void enterA4(OrderState from, OrderState to, OrderEvent event, Order context) { 43 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 44 | } 45 | 46 | @Override 47 | public void enterA4a(OrderState from, OrderState to, OrderEvent event, Order context) { 48 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 49 | } 50 | 51 | @Override 52 | public void fromAToA1(OrderState from, OrderState to, OrderEvent event, Order context) { 53 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 54 | } 55 | 56 | @Override 57 | public void fromA1ToA2(OrderState from, OrderState to, OrderEvent event, Order context) { 58 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 59 | } 60 | 61 | @Override 62 | public void fromA2ToA3(OrderState from, OrderState to, OrderEvent event, Order context) { 63 | System.out.println(this.name); 64 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 65 | } 66 | 67 | @Override 68 | public void fromA3ToA4(OrderState from, OrderState to, OrderEvent event, Order context) { 69 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 70 | } 71 | 72 | @Override 73 | public void exitA1(OrderState from, OrderState to, OrderEvent event, Order context) { 74 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 75 | } 76 | 77 | @Override 78 | public void exitA2(OrderState from, OrderState to, OrderEvent event, Order context) { 79 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 80 | } 81 | 82 | @Override 83 | public void exitA3(OrderState from, OrderState to, OrderEvent event, Order context) { 84 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 85 | } 86 | 87 | @Override 88 | public void exitA4(OrderState from, OrderState to, OrderEvent event, Order context) { 89 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 90 | } 91 | 92 | @Override 93 | public void beforeTransitionBegin(OrderState from, OrderEvent event, Order context) { 94 | //order do 95 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 96 | super.beforeTransitionBegin(from, event, context); 97 | } 98 | 99 | @Override 100 | public void afterTransitionCompleted(OrderState from, OrderState to, OrderEvent event, Order context) { 101 | //order do 102 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 103 | super.afterTransitionCompleted(from, to, event, context); 104 | } 105 | 106 | @Override 107 | public void afterTransitionDeclined(OrderState from, OrderEvent event, Order context) { 108 | //order do 109 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 110 | super.afterTransitionDeclined(from, event, context); 111 | } 112 | 113 | @Override 114 | public void afterTransitionCausedException(OrderState fromState, OrderState toState, OrderEvent event, Order context) { 115 | //order do 116 | System.out.println("当前执行方法:" + Thread.currentThread().getStackTrace()[1].getMethodName()); 117 | super.afterTransitionCausedException(fromState, toState, event, context); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/client/v2/OrderStateMachineV2.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.client.v2; 2 | 3 | import com.github.middleware.fsm.client.constants.OrderState; 4 | import com.github.middleware.fsm.config.annotation.*; 5 | import com.github.middleware.fsm.builder.dto.Order; 6 | import com.github.middleware.fsm.builder.machine.support.visit.StateMachineProxy; 7 | import com.github.middleware.fsm.client.constants.OrderEvent; 8 | /** 9 | * Created by netuser on 17-6-6. 10 | */ 11 | @States({ 12 | @State(name = "A", isInitial = true), 13 | @State(name = "A1", entryMethod = "enterA1", exitMethod = "exitA1"), 14 | @State(name = "A2", entryMethod = "enterA2", exitMethod = "exitA2"), 15 | @State(name = "A3", entryMethod = "enterA3", exitMethod = "exitA3"), 16 | @State(name = "A4", entryMethod = "enterA4", exitMethod = "exitA4"), 17 | @State(name = "A4a", parent = "A4", entryMethod = "enterA4a", exitMethod = "exitA5a", isEnd = true) 18 | }) 19 | @Transitions({ 20 | @Transition(from = "A", to = "A1", on = "ATA1", complete = "fromAToA1", whenMVEL = "PriceChecker::context.price>0&&context.price<100000"), 21 | @Transition(from = "A1", to = "A2", on = "A1TA2", complete = "fromA1ToA2"), 22 | @Transition(from = "A2", to = "A3", on = "A2TA3", complete = "fromA2ToA3"), 23 | @Transition(from = "A3", to = "A4", on = "A3TA4", complete = "fromA3ToA4") 24 | }) 25 | @StateMachineParameters(stateType = OrderState.class, eventType = OrderEvent.class, contextType = Order.class) 26 | public interface OrderStateMachineV2 extends StateMachineProxy { 27 | // entry states 28 | void enterA1(OrderState from, OrderState to, OrderEvent event, Order context); 29 | 30 | void enterA2(OrderState from, OrderState to, OrderEvent event, Order context); 31 | 32 | void enterA3(OrderState from, OrderState to, OrderEvent event, Order context); 33 | 34 | void enterA4(OrderState from, OrderState to, OrderEvent event, Order context); 35 | 36 | void enterA4a(OrderState from, OrderState to, OrderEvent event, Order context); 37 | 38 | // transitions 39 | void fromAToA1(OrderState from, OrderState to, OrderEvent event, Order context); 40 | 41 | void fromA1ToA2(OrderState from, OrderState to, OrderEvent event, Order context); 42 | 43 | void fromA2ToA3(OrderState from, OrderState to, OrderEvent event, Order context); 44 | 45 | void fromA3ToA4(OrderState from, OrderState to, OrderEvent event, Order context); 46 | 47 | // exit states 48 | void exitA1(OrderState from, OrderState to, OrderEvent event, Order context); 49 | 50 | void exitA2(OrderState from, OrderState to, OrderEvent event, Order context); 51 | 52 | void exitA3(OrderState from, OrderState to, OrderEvent event, Order context); 53 | 54 | void exitA4(OrderState from, OrderState to, OrderEvent event, Order context); 55 | 56 | void beforeTransitionBegin(OrderState from, OrderEvent event, Order context); 57 | 58 | void afterTransitionCompleted(OrderState from, OrderState to, OrderEvent event, Order context); 59 | 60 | void afterTransitionDeclined(OrderState from, OrderEvent event, Order context); 61 | 62 | void afterTransitionCausedException(OrderState fromState, OrderState toState, OrderEvent event, Order context); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/core/Converter_Test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core; 2 | 3 | import com.github.middleware.fsm.core.convert.Converter; 4 | import com.github.middleware.fsm.core.convert.support.ConverterImpl; 5 | import org.junit.Test; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * @author alex.chen 11 | * @version 1.0.0 12 | * @date 2017/3/9 13 | */ 14 | public class Converter_Test { 15 | private Converter converter; 16 | 17 | public enum OrderState { 18 | INIT, 19 | CREATE 20 | } 21 | 22 | public enum OrderEvent { 23 | POSTORDER, 24 | ALIPAY 25 | } 26 | 27 | @Test 28 | public void go_objToString() { 29 | Converter converter = new ConverterImpl(OrderEvent.class); 30 | System.out.println(converter.objToString(OrderEvent.ALIPAY)); 31 | 32 | converter = new ConverterImpl(String.class); 33 | System.out.println(converter.objToString("Sss")); 34 | } 35 | 36 | @Test 37 | public void go_stringToObj() { 38 | converter = new ConverterImpl(OrderState.class); 39 | System.out.println(converter.stringToObj("CREATE")); 40 | 41 | converter = new ConverterImpl(String.class); 42 | System.out.println(converter.stringToObj(new Date().toString())); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/core/DependProvider_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core; 2 | 3 | import com.github.middleware.fsm.core.factory.DependProvider; 4 | import com.github.middleware.fsm.core.support.SwithImpl; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.Matchers.*; 9 | 10 | 11 | /** 12 | * @author alex.chen 13 | * @version 1.0.0 14 | * @date 2017/3/12 15 | */ 16 | public class DependProvider_test { 17 | @Test 18 | public void go_newInstance() { 19 | Swith swith = DependProvider.getInstance().newInstance(Swith.class); 20 | Assert.assertThat(swith, notNullValue()); 21 | 22 | swith = DependProvider.getInstance().newInstance(SwithImpl.class); 23 | Assert.assertThat(swith, instanceOf(SwithImpl.class)); 24 | } 25 | 26 | @Test 27 | public void go_newInstanc_forArg(){ 28 | Swith swith = DependProvider.getInstance().newInstance(Swith.class,new Class[]{String.class}, new Object[]{"Alex"}); 29 | Assert.assertThat(swith,notNullValue()); 30 | Assert.assertThat(swith.getName(),equalTo("Alex")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/core/MvelScriptManager_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core; 2 | 3 | import com.github.middleware.fsm.builder.dto.Order; 4 | import com.github.middleware.fsm.core.el.MvelScriptManager; 5 | import com.github.middleware.fsm.core.factory.DependProvider; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.math.BigDecimal; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author alex.chen 16 | * @version 1.0.0 17 | * @date 2017/3/12 18 | */ 19 | public class MvelScriptManager_test { 20 | private MvelScriptManager mvelScriptManager; 21 | private Order order = new Order(1, "ipad", new BigDecimal(2399)); 22 | private Map vars = new HashMap(); 23 | 24 | @Before 25 | public void initInstance() { 26 | mvelScriptManager = DependProvider.getInstance().newInstance(MvelScriptManager.class); 27 | vars.put("x", new Integer(5)); 28 | vars.put("y", new Integer(10)); 29 | } 30 | 31 | @Test 32 | public void go_evalBoolean() { 33 | boolean isEq = mvelScriptManager.evalBoolean("name=='ipad'", order); 34 | Assert.assertTrue(isEq); 35 | } 36 | 37 | @Test 38 | public void go_eval() { 39 | //get 40 | String name = mvelScriptManager.eval("name", order, String.class); 41 | Assert.assertTrue(name.equals("ipad")); 42 | //calc 43 | Integer calc = mvelScriptManager.eval("x*y", vars, Integer.class); 44 | Assert.assertTrue(calc == 50); 45 | } 46 | 47 | @Test 48 | public void go_compile() { 49 | mvelScriptManager.compile("x*y"); 50 | Integer calc = mvelScriptManager.eval("x*y", vars, Integer.class); 51 | Assert.assertTrue(calc == 50); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/core/ReflectUtil_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core; 2 | 3 | import com.github.middleware.fsm.config.annotation.State; 4 | import com.github.middleware.fsm.config.annotation.States; 5 | import com.github.middleware.fsm.core.utils.ReflectUtil; 6 | import com.github.middleware.fsm.filter.annotation.PostConstruct; 7 | import com.google.common.base.Function; 8 | import com.github.middleware.fsm.builder.machine.support.AbstractStateMachine; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | import java.lang.reflect.Method; 13 | import java.util.List; 14 | 15 | /** 16 | * @author alex.chen 17 | * @version 1.0.0 18 | * @date 2017/3/10 19 | */ 20 | public class ReflectUtil_test { 21 | @Test 22 | public void go_isStateMachineInterface() { 23 | Assert.assertFalse(ReflectUtil.isStateMachineInterface(OrderStateMachine.class)); 24 | } 25 | 26 | @Test 27 | public void go_isStateMachineType() { 28 | Assert.assertTrue(ReflectUtil.isStateMachineType(OrderStateMachine.class)); 29 | } 30 | 31 | @Test 32 | public void go_processStateMachineClass() { 33 | ReflectUtil.processStateMachineClass(OrderStateMachine.class, new DeclareStateFunction()); 34 | 35 | } 36 | 37 | @Test 38 | public void go_getAnnotatedMethods() { 39 | List methods = ReflectUtil.getAnnotatedMethods(ReflectUtil_test.class, PostConstruct.class, new Class[]{String.class}); 40 | Assert.assertTrue(methods.size() == 1); 41 | } 42 | 43 | @PostConstruct 44 | public void postConstruct(String str) { 45 | } 46 | 47 | @PostConstruct 48 | public void postConstruct(int num) { 49 | } 50 | 51 | 52 | private class DeclareStateFunction implements Function, Boolean> { 53 | @Override 54 | public Boolean apply(Class k) { 55 | //buildDeclareState(k.getAnnotation(State.class)); 56 | System.out.println("."); 57 | System.out.println(k.getAnnotation(State.class)); 58 | States states = k.getAnnotation(States.class); 59 | if (states != null && states.value() != null) { 60 | for (State s : states.value()) { 61 | //StateMachineBuilderImpl.this.buildDeclareState(s); 62 | System.out.println("..."); 63 | System.out.println(s); 64 | } 65 | } 66 | return true; 67 | } 68 | } 69 | 70 | public enum OrderState { 71 | INIT, 72 | CREATE, PAY, SEND, SIGN, COMMENT, FINISH, END, 73 | //Choices 74 | AMOUNT_CHECK; 75 | } 76 | 77 | public enum OrderEvent { 78 | POSTORDER, 79 | ALIPAY, 80 | PAYMENT, 81 | SEND, 82 | SIGN, 83 | COMMENT, 84 | DOCHECK 85 | } 86 | 87 | @State(parent = "", name = "INIT", entryMethod = "enterInit", exitMethod = "leftInit") 88 | @States(@State(parent = "", name = "CREATE", entryMethod = "enterCREATE", exitMethod = "leftCREATE")) 89 | class OrderStateMachine extends AbstractStateMachine { 90 | 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/core/Swith.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core; 2 | 3 | /** 4 | * @author alex.chen 5 | * @version 1.0.0 6 | * @date 2017/3/8 7 | */ 8 | public interface Swith { 9 | void on(); 10 | 11 | void off(); 12 | 13 | void setName(String name); 14 | 15 | String getName(); 16 | 17 | void setVersion(String version); 18 | 19 | String getVersion(); 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/core/support/SwithImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.core.support; 2 | 3 | import com.github.middleware.fsm.core.Swith; 4 | 5 | import javax.annotation.PostConstruct; 6 | 7 | /** 8 | * @author alex.chen 9 | * @version 1.0.0 10 | * @date 2017/3/8 11 | */ 12 | public class SwithImpl implements Swith { 13 | private String name; 14 | private String version; 15 | 16 | public SwithImpl() { 17 | } 18 | 19 | public SwithImpl(String name) { 20 | this.name = name; 21 | } 22 | @PostConstruct 23 | public void postConstruct() { 24 | this.name=".."; 25 | version = "0.0"; 26 | } 27 | 28 | @Override 29 | public void on() { 30 | System.out.println(getClass().getSimpleName() + ".on."); 31 | } 32 | 33 | @Override 34 | public void off() { 35 | System.out.println(getClass().getSimpleName() + ".off."); 36 | } 37 | 38 | @Override 39 | public String getName() { 40 | return name; 41 | } 42 | 43 | @Override 44 | public void setName(String name) { 45 | this.name = name; 46 | } 47 | 48 | @Override 49 | public void setVersion(String version) { 50 | this.version = version; 51 | } 52 | 53 | @Override 54 | public String getVersion() { 55 | return version; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/filter/MvelChecker_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter; 2 | 3 | import com.github.middleware.fsm.core.el.MvelScriptManager; 4 | import com.github.middleware.fsm.core.factory.DependProvider; 5 | import com.github.middleware.fsm.filter.validator.PreChecker; 6 | import com.github.middleware.fsm.filter.validator.support.MvelCheckerImpl; 7 | import com.github.middleware.fsm.builder.dto.Order; 8 | import org.junit.Assert; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import java.math.BigDecimal; 13 | 14 | /** 15 | * @author alex.chen 16 | * @version 1.0.0 17 | * @date 2017/3/10 18 | */ 19 | public class MvelChecker_test { 20 | private PreChecker preChecker; 21 | 22 | @Before 23 | public void initInstance() { 24 | MvelScriptManager mvelScriptManager = DependProvider.getInstance().newInstance(MvelScriptManager.class); 25 | preChecker = new MvelCheckerImpl("EqChecker::context.name=='ipad'", mvelScriptManager); 26 | } 27 | 28 | @Test 29 | public void go_eval_when() { 30 | Order order = new Order(1, "ipad", new BigDecimal(100000)); 31 | boolean isEq = preChecker.validate(order); 32 | Assert.assertTrue(isEq); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/github/middleware/fsm/filter/PostProcessor_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.fsm.filter; 2 | 3 | 4 | import com.github.middleware.fsm.core.factory.DependProvider; 5 | import com.github.middleware.fsm.filter.wrapper.PostProcessor; 6 | import com.github.middleware.fsm.filter.wrapper.PostProcessorProvider; 7 | import com.github.middleware.fsm.filter.wrapper.support.PostConstructPostProcessorImpl; 8 | import com.github.middleware.fsm.core.Swith; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | import java.util.List; 13 | 14 | import static org.hamcrest.CoreMatchers.sameInstance; 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.*; 17 | 18 | /** 19 | * @author alex.chen 20 | * @version 1.0.0 21 | * @date 2017/3/12 22 | */ 23 | public class PostProcessor_test { 24 | @Test 25 | public void go_register() { 26 | PostProcessorProvider.getInstance().register(Swith.class, new PostProcessor() { 27 | @Override 28 | public void postProcess(Swith Obj) { 29 | Obj.setName("alex"); 30 | } 31 | }); 32 | Swith swith = DependProvider.getInstance().newInstance(Swith.class); 33 | Assert.assertThat(swith, notNullValue()); 34 | assertThat(swith.getName(), equalTo("alex")); 35 | } 36 | 37 | @Test 38 | public void go_getCallablePostProcessors() { 39 | PostProcessor postProcessor = new PostProcessor() { 40 | @Override 41 | public void postProcess(Object Obj) { 42 | } 43 | }; 44 | PostProcessorProvider.getInstance().register(Swith.class, postProcessor); 45 | List> postProcessors = PostProcessorProvider.getInstance().getProcessors(Swith.class); 46 | Assert.assertThat((PostProcessor) postProcessors.get(0), sameInstance(postProcessor)); 47 | 48 | PostProcessorProvider.getInstance().unRegister(Swith.class); 49 | postProcessors = PostProcessorProvider.getInstance().getProcessors(Swith.class); 50 | Assert.assertThat(postProcessors, empty()); 51 | } 52 | 53 | @Test 54 | public void testCompositePostProssor() { 55 | PostProcessor p1 = new PostProcessor() { 56 | @Override 57 | public void postProcess(Swith p) { 58 | p.setName("Alex"); 59 | } 60 | }; 61 | PostProcessor p2 = new PostProcessor() { 62 | @Override 63 | public void postProcess(Swith p) { 64 | p.setVersion("0.1"); 65 | } 66 | }; 67 | PostProcessorProvider.getInstance().register(Swith.class, p1); 68 | PostProcessorProvider.getInstance().register(Swith.class, p2); 69 | List> studentPostProcessors = PostProcessorProvider.getInstance().getProcessors(Swith.class); 70 | assertThat(studentPostProcessors.size(), is(1)); 71 | Swith student = DependProvider.getInstance().newInstance(Swith.class); 72 | assertThat(student.getName(), equalTo("Alex")); 73 | assertThat(student.getVersion(), equalTo("0.1")); 74 | } 75 | 76 | @Test 77 | public void go_postConstruct() { 78 | PostProcessorProvider.getInstance().register(Swith.class, PostConstructPostProcessorImpl.class); 79 | Swith p = DependProvider.getInstance().newInstance(Swith.class); 80 | assertThat(p.getName(), equalTo("..")); 81 | assertThat(p.getVersion(), equalTo("0.0")); 82 | } 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/test/resources/spring-statemachine.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------