├── halo-core ├── src │ ├── main │ │ ├── resources │ │ │ └── sample.properties │ │ └── java │ │ │ └── org │ │ │ └── xujin │ │ │ └── halo │ │ │ ├── pattern │ │ │ └── filter │ │ │ │ ├── Filter.java │ │ │ │ ├── FilterInvoker.java │ │ │ │ ├── FilterChain.java │ │ │ │ └── FilterChainFactory.java │ │ │ ├── assembler │ │ │ ├── AntiCorruptionI.java │ │ │ └── AssemblerI.java │ │ │ ├── boot │ │ │ ├── RegisterI.java │ │ │ ├── ClassNameComparator.java │ │ │ ├── ComponentExecutor.java │ │ │ ├── ClassInterfaceChecker.java │ │ │ ├── PlainRuleRegister.java │ │ │ ├── PlainValidatorRegister.java │ │ │ ├── Bootstrap.java │ │ │ ├── PreInterceptorRegister.java │ │ │ ├── PostInterceptorRegister.java │ │ │ ├── EventRegister.java │ │ │ ├── AbstractRegister.java │ │ │ ├── ExtensionRegister.java │ │ │ └── RegisterFactory.java │ │ │ ├── command │ │ │ ├── QueryExecutorI.java │ │ │ ├── CommandExecutorI.java │ │ │ ├── PostInterceptor.java │ │ │ ├── PreInterceptor.java │ │ │ ├── Command.java │ │ │ ├── CommandBusI.java │ │ │ ├── CommandInterceptorI.java │ │ │ ├── CommandHub.java │ │ │ ├── CommandInvocation.java │ │ │ └── CommandBus.java │ │ │ ├── repository │ │ │ ├── RepositoryI.java │ │ │ ├── DataObject.java │ │ │ └── DataTunnel.java │ │ │ ├── extensionpoint │ │ │ └── MqEventConsumerExtPt.java │ │ │ ├── extension │ │ │ ├── ExtensionPointI.java │ │ │ ├── ExtensionRepository.java │ │ │ ├── Extension.java │ │ │ ├── ExtensionCoordinate.java │ │ │ └── ExtensionExecutor.java │ │ │ ├── common │ │ │ ├── DefaultBizCode.java │ │ │ ├── LocalAddress.java │ │ │ ├── CoreConstant.java │ │ │ └── ApplicationContextHelper.java │ │ │ ├── exception │ │ │ ├── ErrorCodeI.java │ │ │ ├── InfraException.java │ │ │ ├── BizException.java │ │ │ ├── SystemException.java │ │ │ ├── ParamException.java │ │ │ ├── HaloException.java │ │ │ ├── Preconditions.java │ │ │ └── BasicErrorCode.java │ │ │ ├── validator │ │ │ ├── ValidatorI.java │ │ │ ├── PlainValidatorRepository.java │ │ │ ├── HaloMessageInterpolator.java │ │ │ ├── ValidatorExecutor.java │ │ │ └── ValidatorCompoiste.java │ │ │ ├── event │ │ │ ├── EventHandler.java │ │ │ ├── EventHandlerI.java │ │ │ ├── EventBusI.java │ │ │ └── EventHub.java │ │ │ ├── rule │ │ │ ├── ruleengine │ │ │ │ ├── NotRule.java │ │ │ │ ├── OrRule.java │ │ │ │ ├── AndRule.java │ │ │ │ └── AbstractRule.java │ │ │ ├── PlainRuleRepository.java │ │ │ ├── RuleI.java │ │ │ └── RuleExecutor.java │ │ │ ├── logger │ │ │ ├── SysLogger.java │ │ │ ├── SLFJLogger.java │ │ │ ├── LoggerFactory.java │ │ │ └── Logger.java │ │ │ ├── convertor │ │ │ └── ConvertorI.java │ │ │ └── context │ │ │ ├── TenantContext.java │ │ │ └── PvgContext.java │ └── test │ │ ├── resources │ │ └── sample.properties │ │ └── java │ │ └── org │ │ └── xujin │ │ └── halo │ │ ├── test │ │ ├── customer │ │ │ ├── CustomerType.java │ │ │ ├── entity │ │ │ │ ├── SourceType.java │ │ │ │ ├── rule │ │ │ │ │ ├── CustomerBizTwoRuleExt.java │ │ │ │ │ ├── CustomerRuleExtPt.java │ │ │ │ │ └── CustomerBizOneRuleExt.java │ │ │ │ └── CustomerEntity.java │ │ │ ├── GetOneCustomerQry.java │ │ │ ├── validator │ │ │ │ ├── extensionpoint │ │ │ │ │ └── AddCustomerValidatorExtPt.java │ │ │ │ └── extension │ │ │ │ │ ├── AddCustomerBizTwoValidator.java │ │ │ │ │ └── AddCustomerBizOneValidator.java │ │ │ ├── CustomerServiceI.java │ │ │ ├── AddCustomerCmd.java │ │ │ ├── CustomerCO.java │ │ │ ├── CustomerDO.java │ │ │ ├── convertor │ │ │ │ ├── CustomerConvertorExtPt.java │ │ │ │ ├── CustomerConvertor.java │ │ │ │ ├── CustomerBizTwoConvertorExt.java │ │ │ │ └── CustomerBizOneConvertorExt.java │ │ │ ├── interceptor │ │ │ │ ├── ContextInterceptor.java │ │ │ │ └── ValidationInterceptor.java │ │ │ ├── repository │ │ │ │ └── CustomerRepository.java │ │ │ ├── Constants.java │ │ │ ├── CustomerServiceImpl.java │ │ │ └── AddCustomerCmdExe.java │ │ ├── SpringConfigTest.java │ │ └── EntityPrototypeTest.java │ │ └── TestConfig.java └── pom.xml ├── halo-starter ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── spring.factories │ │ └── java │ │ └── org │ │ └── xujin │ │ └── halo │ │ └── boot │ │ └── HaloAutoConfiguration.java └── pom.xml ├── halo-event ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── spring.factories │ │ └── java │ │ └── org │ │ └── xujin │ │ └── halo │ │ └── event │ │ ├── extension │ │ ├── ListenerType.java │ │ ├── EventTypeResolver.java │ │ ├── support │ │ │ ├── BizListenerType.java │ │ │ ├── ClassEventTypeResolver.java │ │ │ └── ClassListenResolver.java │ │ └── ListenResolver.java │ │ ├── EventPublisher.java │ │ ├── boot │ │ ├── EventBusAutoConfiguration.java │ │ └── EventBusConfiguration.java │ │ ├── annotation │ │ ├── listener │ │ │ ├── Listener.java │ │ │ └── Listen.java │ │ ├── BizListener.java │ │ └── Listen.java │ │ ├── publisher │ │ └── DefaultEventPublisher.java │ │ ├── bus │ │ ├── EventBusesHolder.java │ │ └── EventBus.java │ │ └── listener │ │ ├── ListenersHolder.java │ │ └── ListenerParser.java └── pom.xml ├── halo-flow ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── spring.factories │ │ └── java │ │ └── org │ │ └── xujin │ │ └── halo │ │ └── flow │ │ ├── annotation │ │ ├── flow │ │ │ ├── TargetMapping.java │ │ │ ├── EndNode.java │ │ │ ├── Node.java │ │ │ ├── ProcessNode.java │ │ │ ├── StartNode.java │ │ │ ├── WaitNode.java │ │ │ ├── StateNode.java │ │ │ └── Flow.java │ │ ├── transaction │ │ │ ├── LockTarget.java │ │ │ ├── FlowTx.java │ │ │ └── InsertTarget.java │ │ ├── processor │ │ │ ├── ProcessorEnd.java │ │ │ ├── ProcessorAfter.java │ │ │ ├── ProcessorBefore.java │ │ │ ├── ProcessorError.java │ │ │ ├── ProcessorExecute.java │ │ │ └── Processor.java │ │ └── listener │ │ │ ├── FlowListener.java │ │ │ ├── TheFlowListener.java │ │ │ ├── ListenNodeDecided.java │ │ │ └── ListenFlowException.java │ │ ├── listener │ │ ├── FlowListenerType.java │ │ ├── TheFlowEventType.java │ │ ├── TheFlowListenerType.java │ │ ├── DefaultFlowListener.java │ │ ├── ListenNodeDecidedResolver.java │ │ └── ListenFlowExceptionResolver.java │ │ ├── boot │ │ ├── FlowEngineAutoConfiguration.java │ │ └── FlowEngineConfiguration.java │ │ ├── event │ │ ├── NodeDecidedEvent.java │ │ └── FlowExceptionEvent.java │ │ ├── FlowEngine.java │ │ ├── engine │ │ └── TargetContext.java │ │ ├── processor │ │ ├── ProcessorsHolder.java │ │ └── ProcessorParser.java │ │ ├── transaction │ │ ├── TxExecutor.java │ │ ├── FlowTxsHolder.java │ │ └── FlowTxParser.java │ │ └── flow │ │ └── FlowsHolder.java └── pom.xml ├── halo-base ├── src │ └── main │ │ └── java │ │ └── org │ │ └── xujin │ │ └── halo │ │ ├── domain │ │ ├── ValueObject.java │ │ ├── ServiceI.java │ │ ├── DomainFactoryI.java │ │ └── Entity.java │ │ └── annotation │ │ ├── command │ │ ├── Command.java │ │ ├── PreInterceptor.java │ │ └── PostInterceptor.java │ │ └── domian │ │ ├── DomainAbility.java │ │ ├── Domain.java │ │ └── DomainService.java └── pom.xml ├── halo-common ├── src │ └── main │ │ └── java │ │ └── org │ │ └── xujin │ │ └── halo │ │ ├── dto │ │ ├── event │ │ │ ├── EventType.java │ │ │ ├── MqEvent.java │ │ │ └── Event.java │ │ ├── Query.java │ │ ├── DTO.java │ │ ├── OrderDesc.java │ │ ├── Command.java │ │ ├── ClientObject.java │ │ ├── SingleResponse.java │ │ ├── PageQuery.java │ │ ├── Response.java │ │ └── MultiResponse.java │ │ └── method │ │ └── MethodExecutor.java └── pom.xml ├── .gitignore ├── halo-collection ├── src │ └── main │ │ └── java │ │ └── org │ │ └── xujin │ │ └── halo │ │ └── domain │ │ └── DomainUtils.java └── pom.xml ├── halo-test └── pom.xml ├── halo-utils ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── xujin │ └── halo │ └── utils │ └── reflect │ └── BeanMapper.java └── README.md /halo-core/src/main/resources/sample.properties: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /halo-core/src/test/resources/sample.properties: -------------------------------------------------------------------------------- 1 | bizCode=BIZ_ONE 2 | -------------------------------------------------------------------------------- /halo-starter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | org.xujin.halo.boot.HaloAutoConfiguration -------------------------------------------------------------------------------- /halo-event/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | org.xujin.halo.event.boot.EventBusAutoConfiguration -------------------------------------------------------------------------------- /halo-flow/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | org.xujin.halo.flow.boot.FlowEngineAutoConfiguration -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/domain/ValueObject.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.domain; 2 | 3 | /** 4 | * 领域值对象 5 | * @author xujin 6 | * 7 | */ 8 | public interface ValueObject { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/domain/ServiceI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.domain; 2 | 3 | /** 4 | * 领域服务,继承自DomainServiceI的接口都认为是DomainAbility 5 | * @author xujin 6 | * 7 | */ 8 | public interface ServiceI { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/pattern/filter/Filter.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.pattern.filter; 2 | 3 | /** 4 | * 5 | */ 6 | public interface Filter { 7 | 8 | void doFilter(Object context, FilterInvoker nextFilter); 9 | 10 | } -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/domain/DomainFactoryI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.domain; 2 | 3 | /** 4 | * 领域工厂 5 | * @author xujin 6 | * 7 | */ 8 | public interface DomainFactoryI { 9 | 10 | T create(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/event/EventType.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto.event; 2 | 3 | /** 4 | * @author xujin 5 | * @date 2018/04/21 6 | */ 7 | public enum EventType { 8 | CREATE, 9 | UPDATE, 10 | DELETE 11 | ; 12 | } 13 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/assembler/AntiCorruptionI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.assembler; 2 | 3 | /** 4 | * 防腐层 5 | * 适用于消息,查询,RPC等接口的参数装配 6 | * @author xujin 7 | * @date 2018/04/27 8 | */ 9 | public interface AntiCorruptionI { 10 | } 11 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/RegisterI.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.boot; 3 | 4 | 5 | /** 6 | * Register Interface 7 | * @author xujin 8 | */ 9 | public interface RegisterI { 10 | public void doRegistration(Class targetClz); 11 | } 12 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/event/MqEvent.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto.event; 2 | 3 | /** 4 | * 5 | * @author xujin 6 | * @date 2018/05/17 7 | */ 8 | public abstract class MqEvent extends Event { 9 | 10 | public abstract String getTopic(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/pattern/filter/FilterInvoker.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.pattern.filter; 2 | 3 | /** 4 | * @author xujin 5 | * @date 2018/04/17 6 | */ 7 | public interface FilterInvoker { 8 | 9 | default public void invoke(Object context){}; 10 | } 11 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/extension/ListenerType.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.extension; 2 | 3 | /** 4 | * 监听器类型 5 | */ 6 | public interface ListenerType { 7 | 8 | /** 9 | * 获取事件类型解决器 10 | */ 11 | EventTypeResolver getResolver(); 12 | } 13 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/QueryExecutorI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.xujin.halo.dto.Command; 4 | import org.xujin.halo.dto.Response; 5 | 6 | public interface QueryExecutorI extends CommandExecutorI{ 7 | 8 | } 9 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/EventPublisher.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event; 2 | 3 | /** 4 | * 事件发布器 5 | */ 6 | public interface EventPublisher { 7 | 8 | /** 9 | * 发布事件 10 | * 11 | * @param event 事件 12 | */ 13 | void publish(Object event); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/repository/RepositoryI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.repository; 2 | 3 | /** 4 | * This is Repository pattern which decouples the data access from concrete data tunnels. 5 | * 6 | * @author xujin 2017年10月27日 上午11:07:26 7 | */ 8 | public interface RepositoryI { 9 | } 10 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/CustomerType.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | /** 4 | * CustomerType 5 | * 6 | * @author xujin 2018-01-06 7:35 PM 7 | */ 8 | public enum CustomerType { 9 | POTENTIAL, 10 | INTENTIONAL, 11 | IMPORTANT, 12 | VIP; 13 | } 14 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/extensionpoint/MqEventConsumerExtPt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.extensionpoint; 2 | 3 | import org.xujin.halo.dto.Response; 4 | 5 | /** 6 | * 消息消费扩展点 7 | * @author xujin 8 | * 9 | */ 10 | public interface MqEventConsumerExtPt { 11 | 12 | Response receive(String msg); 13 | } 14 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/extension/ExtensionPointI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.extension; 2 | 3 | /** 4 | * ExtensionPointI is the parent interface of all ExtensionPoints 5 | * 扩展点表示一块逻辑在不同的业务有不同的实现,使用扩展点做接口申明,然后用Extension(扩展)去实现扩展点。 6 | * @author xujin 7 | */ 8 | public interface ExtensionPointI { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/entity/SourceType.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.entity; 2 | 3 | /** 4 | * SourceType 5 | * 6 | * @author xujin 7 | * @date 2018-01-07 3:02 AM 8 | */ 9 | public enum SourceType { 10 | AD, //Advertisement 广告 11 | WB, // Web site 网站 12 | RFQ; // Request For Quota 询盘 13 | } 14 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/common/DefaultBizCode.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.common; 3 | 4 | /** 5 | * For App BizCode, please define it in your own App, this is for Framework only 6 | * @author xujin 7 | */ 8 | public class DefaultBizCode { 9 | 10 | public final static String DEFAULT_BIZ_CODE = "$defaultBizCode$"; 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/extension/EventTypeResolver.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.extension; 2 | 3 | /** 4 | * 事件类型解决器 5 | */ 6 | public interface EventTypeResolver { 7 | 8 | /** 9 | * 根据事件得到对应的事件类型 10 | * 11 | * @param event 事件 12 | * @return 事件类型 13 | */ 14 | Object resolve(Object event); 15 | } 16 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/annotation/command/Command.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.annotation.command; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | @Inherited 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE}) 10 | @Component 11 | public @interface Command { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /halo-starter/src/main/java/org/xujin/halo/boot/HaloAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | @Configuration 7 | @ComponentScan(basePackages = {"org.xujin.halo"}) 8 | public class HaloAutoConfiguration { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/Query.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | /** 4 | * 5 | * Query is a special Command which will directly call DataTunnel for data objects 6 | * 7 | * @author xujin 2017年10月22日 下午7:26:49 8 | */ 9 | public abstract class Query extends Command{ 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/CommandExecutorI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.xujin.halo.dto.Command; 4 | import org.xujin.halo.dto.Response; 5 | 6 | /** 7 | * 8 | * CommandExecutorI 9 | * 10 | * @author xujin 11 | */ 12 | public interface CommandExecutorI { 13 | 14 | public R execute(C cmd); 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### BUILD ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | bin/ 25 | doc/ 26 | target/ 27 | out/ 28 | .DS_Store 29 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/ErrorCodeI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | /** 4 | * Extends your error codes in your App by implements this Interface. 5 | * 6 | * Created by xujin on 2018/4/18. 7 | */ 8 | public interface ErrorCodeI { 9 | 10 | public String getErrCode(); 11 | 12 | public String getErrDesc(); 13 | 14 | public boolean isRetriable(); 15 | } 16 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/validator/ValidatorI.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.validator; 3 | 4 | /** 5 | * Validator Interface 6 | * @author xujin 2017-11-04 7 | */ 8 | public interface ValidatorI { 9 | 10 | /** 11 | * Validate candidate, throw according exception if failed 12 | * @param candidate 13 | */ 14 | public void validate(Object candidate); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/GetOneCustomerQry.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | import org.xujin.halo.dto.Query; 4 | import lombok.Data; 5 | 6 | /** 7 | * GetOneCustomerQry 8 | * 9 | * @author xujin 2018-01-06 7:38 PM 10 | */ 11 | @Data 12 | public class GetOneCustomerQry extends Query{ 13 | private long customerId; 14 | private String companyName; 15 | } 16 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/event/EventHandler.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 事件处理器 9 | * @author xujin 10 | * @date 2018/5/20 11 | */ 12 | @Inherited 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target({ElementType.TYPE}) 15 | @Component 16 | public @interface EventHandler { 17 | } 18 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/repository/DataObject.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.repository; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * This is the parent of all Data Objects. 7 | * Data object only has fields and according getters and setters, you can also call it anemic objects 8 | * @author xujin 2017年10月27日 上午10:21:01 9 | */ 10 | public interface DataObject extends Serializable { 11 | } 12 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/TargetMapping.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 目标对象映射 7 | *

8 | * 流程开启执行前会自动调用此注解对应的方法,将目标对象映射到开始执行的流程节点。 9 | * 每次开启新事务时都会调用它将目标对象映射到流程节点 10 | */ 11 | @Documented 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface TargetMapping { 15 | } 16 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/DTO.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Data Transfer object, including Command, Query and Response, 7 | * 8 | * Command and Query is CQRS concept. 9 | * 10 | * @author xujin 2017年10月21日 下午8:53:55 11 | */ 12 | public class DTO implements Serializable{ 13 | 14 | private static final long serialVersionUID = 1L; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/transaction/LockTarget.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.transaction; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 锁目标对象 7 | *

8 | * 流程引擎每次开启新事务时都会调用@LockTarget类型方法,用于锁住目标对象 9 | * 注意:锁住目标对象后,应该更新目标对象到目标上下文 10 | */ 11 | @Documented 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface LockTarget { 15 | } 16 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/PostInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | @Inherited 8 | @Component 9 | @Target({ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface PostInterceptor { 12 | 13 | Class[] commands() default {}; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/PreInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | @Inherited 8 | @Component 9 | @Target({ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface PreInterceptor { 12 | 13 | Class[] commands() default {}; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/annotation/domian/DomainAbility.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.annotation.domian; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 领域能力,用来描述领域实体的行为 9 | * @author xujin 10 | * 11 | */ 12 | @Inherited 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target({ElementType.METHOD}) 15 | @Component 16 | public @interface DomainAbility { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/processor/ProcessorEnd.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.processor; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 结束处理(可选) 7 | *

8 | * 无论是否发生异常都会执行. 9 | * 入参必须是TargetContext类型,返回值必须是void(比如:void end(TargetContext targetContext)) 10 | */ 11 | @Documented 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ProcessorEnd { 15 | } 16 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/annotation/command/PreInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.annotation.command; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | @Inherited 8 | @Component 9 | @Target({ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface PreInterceptor { 12 | 13 | Class[] commands() default {}; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/annotation/command/PostInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.annotation.command; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | @Inherited 8 | @Component 9 | @Target({ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface PostInterceptor { 12 | 13 | Class[] commands() default {}; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/processor/ProcessorAfter.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.processor; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 后置处理(可选) 7 | *

8 | * 一般是业务处理后的收尾工作。 9 | * 入参必须是TargetContext类型,返回值必须是void(比如:void after(TargetContext targetContext)) 10 | */ 11 | @Documented 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ProcessorAfter { 15 | } 16 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/processor/ProcessorBefore.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.processor; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 前置处理(可选) 7 | *

8 | * 一般进行预处理,比如一些预校验。 9 | * 入参必须是TargetContext类型,返回值必须是void(比如:void before(TargetContext targetContext)) 10 | */ 11 | @Documented 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ProcessorBefore { 15 | } 16 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/pattern/filter/FilterChain.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.pattern.filter; 2 | 3 | /** 4 | * 拦截器链 5 | * @author xujin 6 | * @date 2018/04/17 7 | */ 8 | public class FilterChain{ 9 | 10 | private FilterInvoker header; 11 | 12 | public void doFilter(Object context){ 13 | header.invoke(context); 14 | } 15 | 16 | public void setHeader(FilterInvoker header) { 17 | this.header = header; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/ClassNameComparator.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import java.util.Comparator; 4 | 5 | public class ClassNameComparator implements Comparator> { 6 | @Override 7 | public int compare(Class o1, Class o2) { 8 | if (o1 == null) 9 | return -1; 10 | if (o2 == null) 11 | return 1; 12 | return o1.getName().compareToIgnoreCase(o2.getName()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/rule/ruleengine/NotRule.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.rule.ruleengine; 2 | 3 | import org.xujin.halo.rule.RuleI; 4 | 5 | /** 6 | * 组合Not的业务规则 7 | * @author xueliang.sxl 8 | * 9 | */ 10 | public class NotRule extends AbstractRule { 11 | RuleI wrapped; 12 | 13 | public NotRule(RuleI x){ 14 | wrapped = x; 15 | } 16 | 17 | @Override 18 | public boolean check(Object candidate) { 19 | return !wrapped.check(candidate); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/validator/extensionpoint/AddCustomerValidatorExtPt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.validator.extensionpoint; 2 | 3 | import org.xujin.halo.extension.ExtensionPointI; 4 | import org.xujin.halo.validator.ValidatorI; 5 | 6 | /** 7 | * AddCustomerValidatorExtPt 8 | * 9 | * @author xujin 10 | * @date 2018-01-07 1:27 AM 11 | */ 12 | public interface AddCustomerValidatorExtPt extends ValidatorI, ExtensionPointI { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/extension/support/BizListenerType.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.extension.support; 2 | 3 | import org.xujin.halo.event.extension.EventTypeResolver; 4 | import org.xujin.halo.event.extension.ListenerType; 5 | 6 | /** 7 | * biz监听器类型 8 | */ 9 | public class BizListenerType implements ListenerType { 10 | 11 | @Override 12 | public EventTypeResolver getResolver() { 13 | return ClassEventTypeResolver.INSTANCE; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/boot/EventBusAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.boot; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.context.annotation.Import; 5 | 6 | /** 7 | * 事件总线自动配置类 8 | */ 9 | @Configuration 10 | @Import(EventBusConfiguration.class) 11 | public class EventBusAutoConfiguration { 12 | // 事件总线由EventBusConfiguration进行配置 13 | // 本配置类的作用就是在spring-boot项目中自动导入EventBusConfiguration 14 | } 15 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/CustomerServiceI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | import org.xujin.halo.dto.Response; 4 | import org.xujin.halo.dto.SingleResponse; 5 | 6 | /** 7 | * CustomerServiceI 8 | * 9 | * @author xujin 2018-01-06 7:24 PM 10 | */ 11 | public interface CustomerServiceI { 12 | public Response addCustomer(AddCustomerCmd addCustomerCmd); 13 | public SingleResponse getCustomer(GetOneCustomerQry getOneCustomerQry); 14 | } 15 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/transaction/FlowTx.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.transaction; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 流程事务 9 | * (一个流程最多能有一个流程事务类) 10 | */ 11 | @Documented 12 | @Target(ElementType.TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Component 15 | public @interface FlowTx { 16 | 17 | /** 18 | * 对应的流程 19 | */ 20 | String flow(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/extension/ExtensionRepository.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.extension; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.stereotype.Component; 7 | 8 | import lombok.Getter; 9 | 10 | /** 11 | * ExtensionRepository 12 | * @author xujin 13 | */ 14 | @Component 15 | public class ExtensionRepository { 16 | 17 | @Getter 18 | private Map extensionRepo = new HashMap<>(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/AddCustomerCmd.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | 4 | import org.xujin.halo.dto.Command; 5 | import lombok.Data; 6 | 7 | import javax.validation.Valid; 8 | import javax.validation.constraints.NotNull; 9 | 10 | /** 11 | * AddCustomerCmd 12 | * 13 | * @author xujin 2018-01-06 7:28 PM 14 | */ 15 | @Data 16 | public class AddCustomerCmd extends Command { 17 | 18 | @NotNull 19 | @Valid 20 | private CustomerCO customerCO; 21 | } 22 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/processor/ProcessorError.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.processor; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 错误处理(可选) 7 | *

8 | * 在执行@ProcessorBefore、@ProcessorExecute、@ProcessorAfter任何一个发生异常时会执行。 9 | * 入参必须是TargetContext类型,返回值必须是void(比如:void error(TargetContext targetContext)) 10 | */ 11 | @Documented 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ProcessorError { 15 | } 16 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/processor/ProcessorExecute.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.processor; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 业务处理(必需) 7 | *

8 | * 此注解对应的方法返回值会作为处理器的返回值返回给流程节点。 9 | * 入参必须是TargetContext类型;对于返回参数类型的话只要是能被赋值给节点决策器的入参就行 10 | * (比如:String execute(TargetContext targetContext)) 11 | */ 12 | @Documented 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface ProcessorExecute { 16 | } 17 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/Command.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Inherited; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | @Inherited 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target({ElementType.TYPE}) 14 | @Component 15 | public @interface Command { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/rule/PlainRuleRepository.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.rule; 2 | 3 | import lombok.Getter; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * Plain Rule is Rule Component without ExtensionPoint 11 | * @author xujin 12 | * @date 2018/5/21 13 | */ 14 | @Component 15 | public class PlainRuleRepository { 16 | @Getter 17 | private Map, RuleI> plainRules = new HashMap<>(); 18 | } 19 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/rule/ruleengine/OrRule.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.rule.ruleengine; 2 | 3 | import org.xujin.halo.rule.RuleI; 4 | 5 | /** 6 | * 组合Or的业务规则 7 | * @author xueliang.sxl 8 | * 9 | */ 10 | public class OrRule extends AbstractRule { 11 | RuleI one; 12 | RuleI other; 13 | 14 | public OrRule(RuleI x, RuleI y){ 15 | one = x; 16 | other = y; 17 | } 18 | 19 | @Override 20 | public boolean check(Object candidate) { 21 | return one.check(candidate) || other.check(candidate); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/ComponentExecutor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import java.util.function.Function; 4 | 5 | /** 6 | * @author xujin 7 | * @date 2018/4/21 8 | */ 9 | public abstract class ComponentExecutor { 10 | 11 | public R execute(Class targetClz, Function exeFunction) { 12 | C component = locateComponent(targetClz); 13 | return exeFunction.apply(component); 14 | } 15 | 16 | protected abstract C locateComponent(Class targetClz); 17 | } 18 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/CommandBusI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.xujin.halo.dto.Command; 4 | import org.xujin.halo.dto.Response; 5 | 6 | /** 7 | * 8 | * CommandBus 9 | * 10 | * @author xujin 11 | */ 12 | public interface CommandBusI { 13 | 14 | /** 15 | * Send command to CommandBus, then the command will be executed by CommandExecutor 16 | * 17 | * @param Command or Query 18 | * @return Response 19 | */ 20 | public Response send(Command cmd); 21 | } 22 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/rule/ruleengine/AndRule.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.rule.ruleengine; 2 | 3 | import org.xujin.halo.rule.RuleI; 4 | 5 | /** 6 | * 组合And的业务规则 7 | * @author xueliang.sxl 8 | * 9 | */ 10 | public class AndRule extends AbstractRule { 11 | RuleI one; 12 | RuleI other; 13 | 14 | public AndRule(RuleI x, RuleI y){ 15 | one = x; 16 | other = y; 17 | } 18 | 19 | @Override 20 | public boolean check(Object candidate) { 21 | return one.check(candidate) && other.check(candidate); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/rule/RuleI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.rule; 2 | 3 | /** 4 | * 业务规则接口,适合领域层的业务规则检查 5 | * @author xueliang.sxl 6 | * 7 | */ 8 | public interface RuleI { 9 | 10 | /** 11 | * 默认的规则检查接口,子接口可自定义 12 | * @param roleContext 13 | * @return 14 | */ 15 | default boolean check(Object roleContext){ 16 | return true; 17 | } 18 | 19 | /** 20 | * This is specific for Validation cases where no Return is needed 21 | * @param candidate 22 | */ 23 | default void validate(Object... candidate){} 24 | } 25 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/listener/FlowListenerType.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.listener; 2 | 3 | import org.xujin.halo.event.extension.EventTypeResolver; 4 | import org.xujin.halo.event.extension.ListenerType; 5 | import org.xujin.halo.event.extension.support.ClassEventTypeResolver; 6 | 7 | /** 8 | * 流程监听器类型 9 | */ 10 | public class FlowListenerType implements ListenerType { 11 | 12 | @Override 13 | public EventTypeResolver getResolver() { 14 | return ClassEventTypeResolver.INSTANCE; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/common/LocalAddress.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.common; 2 | 3 | import java.net.InetAddress; 4 | import java.net.UnknownHostException; 5 | 6 | /** 7 | * 获取本机地址 8 | * @author xujin 9 | * @date 2018/02/07 10 | */ 11 | public class LocalAddress { 12 | public static String IP = ""; 13 | 14 | static { 15 | try { 16 | IP = InetAddress.getLocalHost().getHostAddress(); 17 | } catch (UnknownHostException e) { 18 | e.printStackTrace(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/rule/ruleengine/AbstractRule.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.rule.ruleengine; 2 | 3 | import org.xujin.halo.rule.RuleI; 4 | 5 | /** 6 | * 业务规则的抽象实现,可用于组合规则 7 | * @author xueliang.sxl 8 | * 9 | */ 10 | public abstract class AbstractRule implements RuleI { 11 | 12 | public RuleI and(RuleI other) { 13 | return new AndRule(this, other); 14 | } 15 | 16 | public RuleI or(RuleI other) { 17 | return new OrRule(this, other); 18 | } 19 | 20 | public RuleI not() { 21 | return new NotRule(this); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/validator/PlainValidatorRepository.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.validator; 2 | 3 | import lombok.Getter; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * Plain Validator is Validator Component without ExtensionPoint 11 | * @author xujin 12 | * @date 2018/6/21 13 | */ 14 | @Component 15 | public class PlainValidatorRepository { 16 | @Getter 17 | private Map, ValidatorI> plainValidators = new HashMap<>(); 18 | } 19 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/assembler/AssemblerI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.assembler; 2 | 3 | 4 | /** 5 | * 适用于消息,查询,RPC等接口的参数装配 6 | * Assembler Interface 7 | * 8 | * @author xujin 9 | */ 10 | public interface AssemblerI extends AntiCorruptionI{ 11 | 12 | default T assembleParam(F from) { 13 | return null; 14 | } 15 | 16 | default void assembleParam(F from, T to) { 17 | } 18 | 19 | default T assembleResult(F from) { 20 | return null; 21 | } 22 | 23 | default void assembleResult(F from, T to) { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/extension/support/ClassEventTypeResolver.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.extension.support; 2 | 3 | import org.xujin.halo.event.extension.EventTypeResolver; 4 | 5 | /** 6 | * Class事件类型解决器(事件类型就是事件对应的Class类) 7 | */ 8 | public class ClassEventTypeResolver implements EventTypeResolver { 9 | /** 10 | * 实例 11 | */ 12 | public static final ClassEventTypeResolver INSTANCE = new ClassEventTypeResolver(); 13 | 14 | @Override 15 | public Object resolve(Object event) { 16 | return event.getClass(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/OrderDesc.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | /** 4 | * Order Description 5 | * 6 | * @author xujin 2018/5/19 7 | */ 8 | public class OrderDesc { 9 | 10 | private String col; 11 | private boolean asc = true; 12 | 13 | public String getCol() { 14 | return col; 15 | } 16 | 17 | public void setCol(String col) { 18 | this.col = col; 19 | } 20 | 21 | public boolean isAsc() { 22 | return asc; 23 | } 24 | 25 | public void setAsc(boolean asc) { 26 | this.asc = asc; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/event/EventHandlerI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event; 2 | 3 | import org.xujin.halo.dto.event.Event; 4 | import org.xujin.halo.dto.Response; 5 | 6 | import java.util.concurrent.Executor; 7 | import java.util.concurrent.ExecutorService; 8 | 9 | /** 10 | * event handler 11 | * 事件处理器的抽象接口 12 | * @author xujin 13 | * @date 2018/6/20 14 | */ 15 | public interface EventHandlerI { 16 | 17 | default public ExecutorService getExecutor(){ 18 | return null; 19 | } 20 | 21 | public R execute(E e); 22 | } 23 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/CustomerCO.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | import org.xujin.halo.dto.ClientObject; 4 | import lombok.Data; 5 | 6 | import javax.validation.constraints.NotEmpty; 7 | 8 | /** 9 | * CustomerCO 10 | * 11 | * @author xujin 2018-01-06 7:30 PM 12 | */ 13 | @Data 14 | public class CustomerCO extends ClientObject{ 15 | 16 | @NotEmpty 17 | private String companyName; 18 | @NotEmpty 19 | private String source; //advertisement, p4p, RFQ, ATM 20 | private CustomerType customerType; //potential, intentional, important, vip 21 | } 22 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/CustomerDO.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | import org.xujin.halo.repository.DataObject; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * CustomerDO 9 | * 10 | * @author xujin 11 | * @date 2018-01-08 1:45 PM 12 | */ 13 | @Data 14 | @EqualsAndHashCode(callSuper = false) 15 | public class CustomerDO implements DataObject { 16 | private String customerId; 17 | private String memberId; 18 | private String globalId; 19 | private String companyName; 20 | private String source; 21 | private String companyType; 22 | } -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/convertor/CustomerConvertorExtPt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.convertor; 2 | 3 | import org.xujin.halo.convertor.ConvertorI; 4 | import org.xujin.halo.extension.ExtensionPointI; 5 | import org.xujin.halo.test.customer.CustomerCO; 6 | import org.xujin.halo.test.customer.entity.CustomerEntity; 7 | 8 | /** 9 | * CustomerConvertorExtPt 10 | * 11 | * @author xujin 12 | * @date 2018-01-07 2:37 AM 13 | */ 14 | public interface CustomerConvertorExtPt extends ConvertorI, ExtensionPointI { 15 | 16 | public CustomerEntity clientToEntity(CustomerCO customerCO); 17 | } 18 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/extension/ListenResolver.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.extension; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * 监听解决器 7 | */ 8 | public interface ListenResolver { 9 | 10 | /** 11 | * 初始化(每个实例仅调用一次) 12 | * 13 | * @param listenMethod 监听方法 14 | */ 15 | void init(Method listenMethod); 16 | 17 | /** 18 | * 获取监听的事件类型 19 | */ 20 | Object getEventType(); 21 | 22 | /** 23 | * 解决调用监听方法的入参 24 | * 25 | * @param event 事件 26 | * @return 调用监听方法的入参 27 | */ 28 | Object[] resolveArgs(Object event); 29 | } 30 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/transaction/InsertTarget.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.transaction; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 插入目标对象到数据库 7 | *

8 | * 本注解的作用:创建一个新事务用来插入目标对象到数据库并提交,前提是调用流程引擎的insertTargetAndStart方法。 9 | * 本注解存在的原因:在开启流程事务情况下,流程引擎是创建新事务进行执行,如果插入目标对象到数据库的事务未提交就执行流程引擎,则流程引擎在锁目标对象时就会出现死锁。 10 | * 所以流程引擎留一个口子新开启一个事务来插入目标对象到数据库。 11 | * 注意:如果插入目标对象时发现目标对象在数据库中已存在,根据幂等性原则,应该使用数据库中的已存在的目标对象(流程引擎是通过锁目标对象来实现)) 12 | */ 13 | @Documented 14 | @Target(ElementType.METHOD) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface InsertTarget { 17 | } 18 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/interceptor/ContextInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.interceptor; 2 | 3 | import org.xujin.halo.command.CommandInterceptorI; 4 | import org.xujin.halo.command.PreInterceptor; 5 | import org.xujin.halo.dto.Command; 6 | 7 | /** 8 | * ContextInterceptor 9 | * 10 | * @author xujin 11 | * @date 2018-01-07 1:21 AM 12 | */ 13 | @PreInterceptor 14 | public class ContextInterceptor implements CommandInterceptorI { 15 | 16 | @Override 17 | public void preIntercept(Command command) { 18 | // TenantContext.set(Constants.TENANT_ID, Constants.BIZ_1); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/repository/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.repository; 2 | 3 | import org.xujin.halo.repository.RepositoryI; 4 | import org.xujin.halo.test.customer.entity.CustomerEntity; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * CustomerRepository 9 | * 10 | * @author xujin 11 | * @date 2018-01-07 11:59 AM 12 | */ 13 | @Repository 14 | public class CustomerRepository implements RepositoryI { 15 | 16 | public void persist(CustomerEntity customerEntity){ 17 | System.out.println("Persist customer to DB : "+ customerEntity); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/InfraException.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | /** 4 | * 5 | * Infrastructure Exception 6 | * 基础设施层异常 7 | * @author xujin 8 | */ 9 | public class InfraException extends HaloException { 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | public InfraException(String errMessage){ 14 | super(errMessage); 15 | this.setErrCode(BasicErrorCode.INFRA_ERROR); 16 | } 17 | 18 | public InfraException(String errMessage, Throwable e) { 19 | super(errMessage, e); 20 | this.setErrCode(BasicErrorCode.INFRA_ERROR); 21 | } 22 | } -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/validator/HaloMessageInterpolator.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.validator; 2 | 3 | import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; 4 | 5 | import java.util.Locale; 6 | 7 | /** 8 | * @author xujin 9 | * @date 2018/6/25 10 | */ 11 | public class HaloMessageInterpolator extends ResourceBundleMessageInterpolator{ 12 | 13 | @Override 14 | public String interpolate(String message, Context context) { 15 | //Use English Locale 16 | String resolvedMessage = super.interpolate(message, context, Locale.ENGLISH); 17 | return resolvedMessage; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/repository/DataTunnel.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.repository; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Data Tunnel is the real Data CRUD Operator may interact with DB, service, cache etc... 7 | * 8 | * @author xujin 2017年10月27日 上午10:34:17 9 | */ 10 | public interface DataTunnel { 11 | 12 | public T create(T dataObject); 13 | 14 | default public void delete(T dataObject) {}; 15 | 16 | default public void update(T dataObject){}; 17 | 18 | default public List list(T entity){return null;}; 19 | 20 | public T get(String id); 21 | 22 | public List getByEntity(T entity); 23 | } 24 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/BizException.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | public class BizException extends HaloException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public BizException(String errMessage){ 8 | super(errMessage); 9 | this.setErrCode(BasicErrorCode.BIZ_ERROR); 10 | } 11 | 12 | public BizException(ErrorCodeI errCode, String errMessage){ 13 | super(errMessage); 14 | this.setErrCode(errCode); 15 | } 16 | 17 | public BizException(String errMessage, Throwable e) { 18 | super(errMessage, e); 19 | this.setErrCode(BasicErrorCode.BIZ_ERROR); 20 | } 21 | } -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/boot/FlowEngineAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.boot; 2 | 3 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.Import; 6 | import org.xujin.halo.event.boot.EventBusAutoConfiguration; 7 | 8 | /** 9 | * 流程引擎自动配置类 10 | */ 11 | @Configuration 12 | @AutoConfigureAfter(EventBusAutoConfiguration.class) 13 | @Import(FlowEngineConfiguration.class) 14 | public class FlowEngineAutoConfiguration { 15 | // 流程引擎由FlowEngineConfiguration进行配置 16 | // 本配置类的作用就是在spring-boot项目中自动导入FlowEngineConfiguration 17 | } 18 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/entity/rule/CustomerBizTwoRuleExt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.entity.rule; 2 | 3 | import org.xujin.halo.extension.Extension; 4 | import org.xujin.halo.test.customer.Constants; 5 | import org.xujin.halo.test.customer.entity.CustomerEntity; 6 | 7 | /** 8 | * CustomerBizTwoRuleExt 9 | * 10 | * @author xujin 11 | * @date 2018-01-07 12:10 PM 12 | */ 13 | @Extension(bizCode = Constants.BIZ_2) 14 | public class CustomerBizTwoRuleExt implements CustomerRuleExtPt{ 15 | 16 | @Override 17 | public boolean addCustomerCheck(CustomerEntity customerEntity) { 18 | //Any Customer can be added 19 | return true; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/annotation/listener/Listener.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.annotation.listener; 2 | 3 | import org.xujin.halo.event.extension.ListenerType; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * 监听器 10 | */ 11 | @Documented 12 | @Target(ElementType.ANNOTATION_TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Component 15 | public @interface Listener { 16 | 17 | /** 18 | * 类型 19 | */ 20 | Class type(); 21 | 22 | /** 23 | * 优先级 24 | * (具体执行顺序需要结合@Listen注解的priorityAsc属性共同决定) 25 | */ 26 | int priority() default Integer.MAX_VALUE; 27 | } 28 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/EndNode.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 结束节点 9 | * (每个流程必须至少有一个结束节点,它是流程结束的标志。当流程跳转到结束节点时,流程会自动结束; 10 | * 对应的节点决策器不能有入参,且返回类型必须是void,决策器的方法体不会被执行) 11 | */ 12 | @Documented 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Node(autoExecute = false, newTx = true) 16 | public @interface EndNode { 17 | 18 | /** 19 | * 节点名称(默认使用被注解的函数名,在一个流程内节点名称需唯一) 20 | */ 21 | @AliasFor(annotation = Node.class, attribute = "name") 22 | String name() default ""; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/annotation/domian/Domain.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.annotation.domian; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 域描述注解 7 | * @author xujin 8 | */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target({ElementType.TYPE}) 11 | @Inherited 12 | public @interface Domain { 13 | 14 | /** 15 | * 当前域的唯一code 16 | * @return 17 | */ 18 | String code(); 19 | 20 | /** 21 | * 父域的唯一code 22 | * @return 23 | */ 24 | String parentCode() default ""; 25 | 26 | /** 27 | * 当前域的名称 28 | * @return 29 | */ 30 | String name(); 31 | 32 | /** 33 | * 当前域的描述 34 | * @return 35 | */ 36 | String desc() default ""; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/event/Event.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto.event; 2 | 3 | import org.xujin.halo.dto.DTO; 4 | 5 | /** 6 | * @author xujin 7 | */ 8 | public class Event extends DTO { 9 | private static final long serialVersionUID = 5740150436439366761L; 10 | protected String eventId; 11 | protected String eventType; 12 | 13 | public String getEventType(){ 14 | return eventType; 15 | } 16 | 17 | public String getEventId(){ 18 | return eventId; 19 | } 20 | 21 | public void setEventId(String eventId) { 22 | this.eventId = eventId; 23 | } 24 | 25 | public void setEventType(String eventType) { 26 | this.eventType = eventType; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/SystemException.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | /** 4 | * 系统异常 5 | * 6 | * @author xujin 7 | */ 8 | public class SystemException extends HaloException { 9 | 10 | private static final long serialVersionUID = 4355163994767354840L; 11 | 12 | public SystemException(String errMessage) { 13 | super(errMessage); 14 | } 15 | 16 | public SystemException(ErrorCodeI errCode, String errMessage) { 17 | super(errMessage); 18 | this.setErrCode(errCode); 19 | } 20 | 21 | public SystemException(String errMessage, ErrorCodeI errorCode, Throwable e) { 22 | super(errMessage, e); 23 | this.setErrCode(errorCode); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/annotation/listener/Listen.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.event.annotation.listener; 3 | 4 | import org.xujin.halo.event.extension.ListenResolver; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * 监听 10 | */ 11 | @Documented 12 | @Target(ElementType.ANNOTATION_TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface Listen { 15 | 16 | /** 17 | * 监听解决器 18 | */ 19 | Class resolver(); 20 | 21 | /** 22 | * 是否按照优先级升序 23 | *

24 | * true:表示升序,即监听器中优先级值越小优先级越高;false:表示降序,即监听器中优先级值越大优先级越高。默认为升序。 25 | * 当一个事件发布时,总是先执行完优先级为升序的监听方法,再执行优先级为降序的监听方法 26 | */ 27 | boolean priorityAsc() default true; 28 | } 29 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/ParamException.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | /** 4 | * 参数异常 5 | */ 6 | public class ParamException extends HaloException { 7 | 8 | private static final long serialVersionUID = 1L; 9 | 10 | public ParamException(String errMessage){ 11 | super(errMessage); 12 | this.setErrCode(BasicErrorCode.PARAM_ERROR); 13 | } 14 | 15 | public ParamException(ErrorCodeI errCode, String errMessage){ 16 | super(errMessage); 17 | this.setErrCode(errCode); 18 | } 19 | 20 | public ParamException(String errMessage, Throwable e) { 21 | super(errMessage, e); 22 | this.setErrCode(BasicErrorCode.PARAM_ERROR); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/Constants.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | /** 4 | * Constants 5 | * 6 | * @author xujin 7 | * @date 2018-01-07 1:23 AM 8 | */ 9 | public class Constants { 10 | 11 | public static final String BIZ_1 = "BIZ_ONE"; 12 | public static final String BIZ_2 = "BIZ_TWO"; 13 | 14 | public static final String TENANT_ID = "122344"; 15 | 16 | 17 | public static final String SOURCE_AD = "Advertisement"; 18 | public static final String SOURCE_WB = "Web site"; 19 | public static final String SOURCE_RFQ = "Request For Quota"; 20 | public static final String SOURCE_MARKETING = "Marketing"; 21 | public static final String SOURCE_OFFLINE = "Off Line"; 22 | } 23 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/listener/FlowListener.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.listener; 2 | 3 | import org.xujin.halo.event.annotation.listener.Listener; 4 | import org.xujin.halo.flow.listener.FlowListenerType; 5 | import org.springframework.core.annotation.AliasFor; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * 流程监听器 11 | * (监听的是所有流程发生的事件) 12 | */ 13 | @Documented 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Listener(type = FlowListenerType.class) 17 | public @interface FlowListener { 18 | 19 | /** 20 | * 优先级 21 | */ 22 | @AliasFor(annotation = Listener.class, attribute = "priority") 23 | int priority() default Integer.MAX_VALUE; 24 | } 25 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/annotation/BizListener.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.annotation; 2 | 3 | import org.xujin.halo.event.annotation.listener.Listener; 4 | import org.xujin.halo.event.extension.support.BizListenerType; 5 | import org.springframework.core.annotation.AliasFor; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * 业务监听器 11 | */ 12 | @Documented 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Listener(type = BizListenerType.class) 16 | public @interface BizListener { 17 | 18 | /** 19 | * 优先级 20 | * (具体执行顺序需要结合@Listen注解的priorityAsc属性共同决定) 21 | */ 22 | @AliasFor(annotation = Listener.class, attribute = "priority") 23 | int priority() default Integer.MAX_VALUE; 24 | } 25 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/processor/Processor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.processor; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 节点处理器 9 | *

10 | * 执行步骤: 11 | * 1、@ProcessorBefore(可选) 12 | * 2、@ProcessorExecute(必需) 13 | * 3、@ProcessorAfter(可选) 14 | * 4、@ProcessorError(可选,如果@ProcessorBefore、@ProcessorExecute、@ProcessorAfter任何一个发生异常则执行@ProcessorError) 15 | * 5、@ProcessorEnd(可选,无论是否发生异常都会执行) 16 | */ 17 | @Documented 18 | @Target(ElementType.TYPE) 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Component 21 | public @interface Processor { 22 | 23 | /** 24 | * 处理器名字(默认使用被注解类的名字,首字母小写) 25 | */ 26 | String name() default ""; 27 | } 28 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/extension/Extension.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.extension; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | import org.xujin.halo.common.CoreConstant; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * Extension 11 | * @author xujin 12 | */ 13 | @Inherited 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.TYPE}) 16 | @Component 17 | public @interface Extension { 18 | 19 | /** 20 | * 一级业务code 21 | * @return 22 | */ 23 | String bizCode() default CoreConstant.DEFAULT_BIZ_CODE; 24 | 25 | /** 26 | * 二级业务code 27 | * @return 28 | */ 29 | String tenantId() default CoreConstant.DEFAULT_TENANT_ID; 30 | } 31 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/HaloException.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | /** 4 | * 5 | * Halo框架抽象异常 6 | * 7 | * @author 8 | */ 9 | public abstract class HaloException extends RuntimeException{ 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | private ErrorCodeI errCode; 14 | 15 | public HaloException(String errMessage){ 16 | super(errMessage); 17 | } 18 | 19 | public HaloException(String errMessage, Throwable e) { 20 | super(errMessage, e); 21 | } 22 | 23 | public ErrorCodeI getErrCode() { 24 | return errCode; 25 | } 26 | 27 | public void setErrCode(ErrorCodeI errCode) { 28 | this.errCode = errCode; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/entity/rule/CustomerRuleExtPt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.entity.rule; 2 | 3 | import org.xujin.halo.extension.ExtensionPointI; 4 | import org.xujin.halo.rule.RuleI; 5 | import org.xujin.halo.test.customer.entity.CustomerEntity; 6 | 7 | /** 8 | * CustomerRuleExtPt 9 | * 10 | * @author xujin 11 | * @date 2018-01-07 12:03 PM 12 | */ 13 | public interface CustomerRuleExtPt extends RuleI, ExtensionPointI { 14 | 15 | //Different business check for different biz 16 | public boolean addCustomerCheck(CustomerEntity customerEntity); 17 | 18 | //Different upgrade policy for different biz 19 | default public void customerUpgradePolicy(CustomerEntity customerEntity){ 20 | //Nothing special 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/publisher/DefaultEventPublisher.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.publisher; 2 | 3 | import org.apache.commons.lang3.exception.ExceptionUtils; 4 | import org.xujin.halo.event.EventPublisher; 5 | import org.xujin.halo.event.bus.EventBus; 6 | 7 | /** 8 | * 事件发布器默认实现类 9 | */ 10 | public class DefaultEventPublisher implements EventPublisher { 11 | // 事件总线 12 | private EventBus eventBus; 13 | 14 | public DefaultEventPublisher(EventBus eventBus) { 15 | this.eventBus = eventBus; 16 | } 17 | 18 | @Override 19 | public void publish(Object event) { 20 | try { 21 | eventBus.dispatch(event); 22 | } catch (Throwable e) { 23 | ExceptionUtils.rethrow(e); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/CommandInterceptorI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.xujin.halo.dto.Command; 4 | import org.xujin.halo.dto.Response; 5 | 6 | /** 7 | * Interceptor will do AOP processing before or after Command Execution 8 | * 9 | * @author xujin 10 | */ 11 | public interface CommandInterceptorI { 12 | 13 | /** 14 | * Pre-processing before command execution 15 | * @param command 16 | */ 17 | default public void preIntercept(Command command){}; 18 | 19 | /** 20 | * Post-processing after command execution 21 | * @param command 22 | * @param response, Note that response could be null, check it before use 23 | */ 24 | default public void postIntercept(Command command, Response response){}; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/TestConfig.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo; 2 | 3 | import org.xujin.halo.boot.Bootstrap; 4 | import org.springframework.context.annotation.*; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * TestConfig 11 | * 12 | * @author xujin 2018-01-06 7:57 AM 13 | */ 14 | @Configuration 15 | @ComponentScan("org.xujin.halo") 16 | @PropertySource(value = {"/sample.properties"}) 17 | public class TestConfig { 18 | 19 | @Bean(initMethod = "init") 20 | public Bootstrap bootstrap() { 21 | Bootstrap bootstrap = new Bootstrap(); 22 | List packagesToScan = new ArrayList<>(); 23 | packagesToScan.add("org.xujin.halo.test"); 24 | bootstrap.setPackages(packagesToScan); 25 | return bootstrap; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/SpringConfigTest.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test; 2 | 3 | import org.xujin.halo.TestConfig; 4 | import org.xujin.halo.boot.Bootstrap; 5 | import org.xujin.halo.boot.RegisterFactory; 6 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 7 | 8 | public class SpringConfigTest { 9 | 10 | public static void main(String[] args) { 11 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class); 12 | Bootstrap bootstrap = (Bootstrap)context.getBean("bootstrap"); 13 | RegisterFactory registerFactory = (RegisterFactory)context.getBean("registerFactory"); 14 | System.out.println(registerFactory); 15 | System.out.println(bootstrap.getPackages()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/Node.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 节点 7 | * (此为节点父注解,StartNode、ProcessNode、StateNode、WaitNode、EndNode都是根据此注解延伸的) 8 | */ 9 | @Documented 10 | @Target(ElementType.ANNOTATION_TYPE) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | public @interface Node { 13 | 14 | /** 15 | * 节点名称(默认使用被注解的函数名,在一个流程内节点名称需唯一) 16 | */ 17 | String name() default ""; 18 | 19 | /** 20 | * 节点处理器(默认不执行处理器) 21 | */ 22 | String processor() default ""; 23 | 24 | /** 25 | * 是否自动执行本节点(默认自动执行) 26 | */ 27 | boolean autoExecute() default true; 28 | 29 | /** 30 | * 本节点执行前是否创建新事务(默认不新建) 31 | */ 32 | boolean newTx() default false; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/common/CoreConstant.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.common; 3 | 4 | /** 5 | * CoreConstant 6 | * @author xujin 7 | */ 8 | public class CoreConstant { 9 | 10 | public final static String DEFAULT_BIZ_CODE = "$defaultBizCode$"; 11 | public final static String DEFAULT_TENANT_ID = "$defaultTenantId$"; 12 | 13 | public final static String EXTENSION_EXTPT_NAMING = "ExtPt"; 14 | public final static String VALIDATOR_NAMING = "Validator"; 15 | public final static String RULE_NAMING = "Rule"; 16 | 17 | public final static String EXTENSIONPOINT_CLASS = "ExtensionPointI"; 18 | public final static String VALIDATORI_CLASS = "ValidatorI"; 19 | public final static String RULEI_CLASS = "RuleI"; 20 | 21 | public final static String EXE_METHOD = "execute"; 22 | } 23 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/logger/SysLogger.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.logger; 2 | 3 | public class SysLogger implements Logger{ 4 | 5 | public static SysLogger singleton = new SysLogger(); 6 | 7 | @Override 8 | public void debug(String msg) { 9 | System.out.println("DEBUG: "+msg); 10 | } 11 | 12 | @Override 13 | public void info(String msg) { 14 | System.out.println("INFO: "+msg); 15 | } 16 | 17 | @Override 18 | public void warn(String msg) { 19 | System.out.println("WARN: "+msg); 20 | } 21 | 22 | @Override 23 | public void error(String msg) { 24 | System.err.println("ERROR: "+msg); 25 | } 26 | 27 | @Override 28 | public void error(String msg, Throwable t) { 29 | System.err.println("ERROR: "+msg); 30 | t.printStackTrace(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/event/EventBusI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event; 2 | 3 | import org.xujin.halo.dto.event.Event; 4 | import org.xujin.halo.dto.Response; 5 | 6 | 7 | /** 8 | * EventBus interface 9 | * @author xujin 10 | * @date 2018/3/20 11 | */ 12 | public interface EventBusI { 13 | 14 | /** 15 | * Send event to EventBus 16 | * 发送事件到事件Bus 17 | * @param event 18 | * @return Response 19 | */ 20 | public Response fire(Event event); 21 | 22 | /** 23 | * fire all handlers which registed the event 24 | * 触发已经注册的所有注册事件对应的处理器 25 | * @param event 26 | * @return Response 27 | */ 28 | public void fireAll(Event event); 29 | 30 | /** 31 | * 异步触发对应注册事件的对应的处理器 32 | * Async fire all handlers 33 | * @param event 34 | */ 35 | public void asyncFire(Event event); 36 | } 37 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/listener/TheFlowListener.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.listener; 2 | 3 | import org.xujin.halo.event.annotation.listener.Listener; 4 | import org.xujin.halo.flow.listener.TheFlowListenerType; 5 | import org.springframework.core.annotation.AliasFor; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * 特定流程监听器 11 | * (监听的是某一个特定流程发生的事件,配合@ListenNodeDecide、@ListenFlowException一起使用) 12 | */ 13 | @Documented 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Listener(type = TheFlowListenerType.class) 17 | public @interface TheFlowListener { 18 | 19 | /** 20 | * 被监听的流程 21 | */ 22 | String flow(); 23 | 24 | /** 25 | * 优先级 26 | */ 27 | @AliasFor(annotation = Listener.class, attribute = "priority") 28 | int priority() default Integer.MAX_VALUE; 29 | } 30 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/ProcessNode.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 处理节点 9 | * (处理节点是一种单纯的处理单元,即使开启了流程事务情况,此类型节点在执行前也不会提交事务; 10 | * 对应的节点决策器返回值类型必须为String,入参类型可为:()、(TargetContext)、(T)、(T, TargetContext)————T表示能被对应的处理器返回结果赋值的类型) 11 | */ 12 | @Documented 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Node 16 | public @interface ProcessNode { 17 | 18 | /** 19 | * 节点名称(默认使用被注解的函数名,在一个流程内节点名称需唯一) 20 | */ 21 | @AliasFor(annotation = Node.class, attribute = "name") 22 | String name() default ""; 23 | 24 | /** 25 | * 节点处理器(默认不执行处理器) 26 | */ 27 | @AliasFor(annotation = Node.class, attribute = "processor") 28 | String processor() default ""; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/listener/ListenNodeDecided.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.listener; 2 | 3 | import org.xujin.halo.event.annotation.listener.Listen; 4 | import org.xujin.halo.flow.listener.ListenNodeDecidedResolver; 5 | import org.springframework.core.annotation.AliasFor; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * 监听节点选择事件 11 | * (配合TheFlowListener一起使用;流程执行过程中,当每次发生节点选择事件时都会调用注入本注解对应的方法; 12 | * 一个TheFlowListener内最多只能出现一次;对应的监听方法入参必须为(String, TargetContext)) 13 | */ 14 | @Documented 15 | @Target(ElementType.METHOD) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Listen(resolver = ListenNodeDecidedResolver.class) 18 | public @interface ListenNodeDecided { 19 | 20 | /** 21 | * 是否按照优先级升序 22 | */ 23 | @AliasFor(annotation = Listen.class, attribute = "priorityAsc") 24 | boolean priorityAsc() default true; 25 | } 26 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/StartNode.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 开始节点 9 | * (每个流程都必须有一个唯一的开始节点,开始节点应该是一个流程象的最开始执行的节点; 10 | * 对应的节点决策器返回值类型必须为String,入参类型可为:()、(TargetContext)、(T)、(T, TargetContext)————T表示能被对应的处理器返回结果赋值的类型) 11 | */ 12 | @Documented 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Node(newTx = true) 16 | public @interface StartNode { 17 | 18 | /** 19 | * 节点名称(默认使用被注解的函数名,在一个流程内节点名称需唯一) 20 | */ 21 | @AliasFor(annotation = Node.class, attribute = "name") 22 | String name() default ""; 23 | 24 | /** 25 | * 节点处理器(默认不执行处理器) 26 | */ 27 | @AliasFor(annotation = Node.class, attribute = "processor") 28 | String processor() default ""; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/annotation/Listen.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.annotation; 2 | 3 | import org.xujin.halo.event.extension.support.ClassListenResolver; 4 | import org.springframework.core.annotation.AliasFor; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * 监听 10 | */ 11 | @Documented 12 | @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @org.xujin.halo.event.annotation.listener.Listen(resolver = ClassListenResolver.class) 15 | public @interface Listen { 16 | 17 | /** 18 | * 是否按照优先级升序 19 | *

20 | * true:表示升序,即监听器中优先级值越小优先级越高;false:表示降序,即监听器中优先级值越大优先级越高。默认为升序。 21 | * 当一个事件发布时,总是先执行完优先级为升序的监听方法,再执行优先级为降序的监听方法 22 | */ 23 | @AliasFor(annotation = org.xujin.halo.event.annotation.listener.Listen.class, attribute = "priorityAsc") 24 | boolean priorityAsc() default true; 25 | } 26 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/listener/ListenFlowException.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.listener; 2 | 3 | import org.xujin.halo.event.annotation.listener.Listen; 4 | import org.xujin.halo.flow.listener.ListenFlowExceptionResolver; 5 | import org.springframework.core.annotation.AliasFor; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * 监听流程异常事件 11 | * (配合TheFlowListener一起使用;当流程执行过程中发生任何异常,都会调用注入本注解对应的方法; 12 | * 一个TheFlowListener内最多只能出现一次;对应的监听方法入参类型必须为(Throwable, TargetContext)) 13 | */ 14 | @Documented 15 | @Target(ElementType.METHOD) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Listen(resolver = ListenFlowExceptionResolver.class) 18 | public @interface ListenFlowException { 19 | 20 | /** 21 | * 是否按照优先级升序 22 | */ 23 | @AliasFor(annotation = Listen.class, attribute = "priorityAsc") 24 | boolean priorityAsc() default true; 25 | } 26 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/convertor/ConvertorI.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.convertor; 2 | 3 | import org.xujin.halo.domain.Entity; 4 | import org.xujin.halo.dto.DTO; 5 | import org.xujin.halo.repository.DataObject; 6 | 7 | /** 8 | * Convertor are used to convert Objects among Client Object, Domain Object and Data Object. 9 | * 10 | * @author xujin 11 | */ 12 | public interface ConvertorI { 13 | 14 | default public T entityToClient(Object... entityObject){return null;} 15 | 16 | default public T dataToClient(Object... dataObject){return null;} 17 | 18 | default public T clientToEntity(Object... clientObject){return null;} 19 | 20 | default public T dataToEntity(Object... dataObject){return null;} 21 | 22 | default public T entityToData(Object... entityObject){return null;} 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/logger/SLFJLogger.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.logger; 2 | 3 | public class SLFJLogger implements Logger { 4 | 5 | private org.slf4j.Logger slfjLogger; 6 | 7 | public SLFJLogger(org.slf4j.Logger slfjLogger) { 8 | this.slfjLogger = slfjLogger; 9 | } 10 | 11 | @Override 12 | public void debug(String msg) { 13 | slfjLogger.debug(msg); 14 | } 15 | 16 | @Override 17 | public void info(String msg) { 18 | slfjLogger.info(msg); 19 | 20 | } 21 | 22 | @Override 23 | public void warn(String msg) { 24 | slfjLogger.warn(msg); 25 | 26 | } 27 | 28 | @Override 29 | public void error(String msg) { 30 | slfjLogger.error(msg); 31 | 32 | } 33 | 34 | @Override 35 | public void error(String msg, Throwable t) { 36 | slfjLogger.error(msg, t); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/ClassInterfaceChecker.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import org.apache.commons.lang3.ArrayUtils; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | /** 7 | * @author xujin 8 | * @date 2018/3/21 9 | */ 10 | public class ClassInterfaceChecker { 11 | 12 | public static boolean check(Class targetClz, String expectedName){ 13 | //If it is not Class, just return false 14 | if(targetClz.isInterface()){ 15 | return false; 16 | } 17 | 18 | Class[] interfaces = targetClz.getInterfaces(); 19 | if (ArrayUtils.isEmpty(interfaces)) 20 | return false; 21 | for (Class intf : interfaces) { 22 | String intfSimpleName = intf.getSimpleName(); 23 | if (StringUtils.equals(intfSimpleName, expectedName)) 24 | return true; 25 | } 26 | return false; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/CustomerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | import org.xujin.halo.command.CommandBusI; 4 | import org.xujin.halo.dto.Response; 5 | import org.xujin.halo.dto.SingleResponse; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * CustomerServiceImpl 11 | * 12 | * @author xujin 2018-01-06 7:40 PM 13 | */ 14 | @Service 15 | public class CustomerServiceImpl implements CustomerServiceI{ 16 | 17 | @Autowired 18 | private CommandBusI commandBus; 19 | 20 | @Override 21 | public Response addCustomer(AddCustomerCmd addCustomerCmd) { 22 | return (Response)commandBus.send(addCustomerCmd); 23 | } 24 | 25 | @Override 26 | public SingleResponse getCustomer(GetOneCustomerQry getOneCustomerQry) { 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/WaitNode.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 等待节点 9 | * (只有当等待节点是第一个被执行的节点,等待节点才会被执行;否则流程执行到等待节点时会正常中断。(这符合等待异步通知这类场景)。 10 | * 对应的节点决策器返回值类型必须为String,入参类型可为:()、(TargetContext)、(T)、(T, TargetContext)————T表示能被对应的处理器返回结果赋值的类型) 11 | */ 12 | @Documented 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Node(autoExecute = false, newTx = true) 16 | public @interface WaitNode { 17 | 18 | /** 19 | * 节点名称(默认使用被注解的函数名,在一个流程内节点名称需唯一) 20 | */ 21 | @AliasFor(annotation = Node.class, attribute = "name") 22 | String name() default ""; 23 | 24 | /** 25 | * 节点处理器(默认不执行处理器) 26 | */ 27 | @AliasFor(annotation = Node.class, attribute = "processor") 28 | String processor() default ""; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/StateNode.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 状态节点 9 | * (对于开启了流程事务情况,状态节点是一个状态开始的标志(需要新事务来执行),也是上一个状态结束的标志(需要提交老事务),所以在状态节点执行前会先提交事务然后开启新事务并锁住目标对象; 10 | * 对应的节点决策器返回值类型必须为String,入参类型可为:()、(TargetContext)、(T)、(T, TargetContext)————T表示能被对应的处理器返回结果赋值的类型) 11 | */ 12 | @Documented 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Node(newTx = true) 16 | public @interface StateNode { 17 | 18 | /** 19 | * 节点名称(默认使用被注解的函数名,在一个流程内节点名称需唯一) 20 | */ 21 | @AliasFor(annotation = Node.class, attribute = "name") 22 | String name() default ""; 23 | 24 | /** 25 | * 节点处理器(默认不执行处理器) 26 | */ 27 | @AliasFor(annotation = Node.class, attribute = "processor") 28 | String processor() default ""; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/entity/rule/CustomerBizOneRuleExt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.entity.rule; 2 | 3 | import org.xujin.halo.exception.BizException; 4 | import org.xujin.halo.extension.Extension; 5 | import org.xujin.halo.test.customer.Constants; 6 | import org.xujin.halo.test.customer.entity.CustomerEntity; 7 | import org.xujin.halo.test.customer.entity.SourceType; 8 | 9 | /** 10 | * CustomerBizOneRuleExt 11 | * 12 | * @author xujin 13 | * @date 2018-01-07 12:10 PM 14 | */ 15 | @Extension(bizCode = Constants.BIZ_1) 16 | public class CustomerBizOneRuleExt implements CustomerRuleExtPt{ 17 | 18 | @Override 19 | public boolean addCustomerCheck(CustomerEntity customerEntity) { 20 | if(SourceType.AD == customerEntity.getSourceType()){ 21 | throw new BizException("Sorry, Customer from advertisement can not be added in this period"); 22 | } 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/annotation/domian/DomainService.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.annotation.domian; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.METHOD}) 10 | public @interface DomainService { 11 | 12 | /** 13 | * 当前域的唯一编码 14 | * @return 15 | */ 16 | String code(); 17 | 18 | /** 19 | * 域服务的名称用于显示 20 | * @return 21 | */ 22 | String name(); 23 | 24 | /** 25 | * 当前域的描述 26 | * @return 27 | */ 28 | String desc() default ""; 29 | 30 | /** 31 | * 当前域服务的帮助url 32 | * @return 33 | */ 34 | String helpUrl() default ""; 35 | 36 | /** 37 | * the domain ability codes 38 | * @return 39 | */ 40 | String[] abilityCodes() default ""; 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/annotation/flow/Flow.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.annotation.flow; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 流程 9 | *

10 | * 流程包含的节点类型:开始节点(@StartNode)、状态节点(@StateNode)、处理节点(@ProcessNode)、等待节点(@WaitNode)、结束节点(@EndNode) 11 | * 一:开启了流程事务情况 12 | * 流程在刚开始执行时会自动的开启一个新事务并调用流程事务锁住目标对象; 13 | * 当流程被正常中断或正常执行结束(无异常抛出),则会提交事务;否则如果有任何异常抛出,则会回滚事务(当然已经提交的那些事务是不会回滚的)。 14 | *

15 | * 二:未开启流程事务情况 16 | * 整个执行过程中流程引擎不会对事务做任何操作(既不会主动开启事务,也不会主动提交事务),也不会调用流程事务锁住目标对象;@StateNode节点效果也会跟@ProcessNode节点效果一样 17 | */ 18 | @Documented 19 | @Target(ElementType.TYPE) 20 | @Retention(RetentionPolicy.RUNTIME) 21 | @Component 22 | public @interface Flow { 23 | 24 | /** 25 | * 流程名称(默认使用被注解的类名,首字母小写) 26 | */ 27 | String name() default ""; 28 | 29 | /** 30 | * 是否开启流程事务(默认开启) 31 | */ 32 | boolean enableFlowTx() default true; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/Preconditions.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | /** 4 | * Preconditions 先决条件 5 | * @author xujin 6 | */ 7 | public class Preconditions { 8 | 9 | public static void checkArgument(boolean expression) { 10 | if (!expression) { 11 | throw new ParamException(""); 12 | } 13 | } 14 | 15 | public static void checkArgument(boolean expression, Object errorMessage) { 16 | if (!expression) { 17 | throw new ParamException(String.valueOf(errorMessage)); 18 | } 19 | } 20 | 21 | public static void checkState(boolean expression) { 22 | if (!expression) { 23 | throw new BizException(""); 24 | } 25 | } 26 | 27 | public static void checkState(boolean expression, Object errorMessage) { 28 | if (!expression) { 29 | throw new BizException(String.valueOf(errorMessage)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/common/ApplicationContextHelper.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.common; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * ApplicationContextHelper 10 | * 11 | * @author xujin 12 | * @date 2018-01-07 12:30 PM 13 | */ 14 | @Component 15 | public class ApplicationContextHelper implements ApplicationContextAware{ 16 | 17 | private static ApplicationContext applicationContext; 18 | 19 | @Override 20 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 21 | ApplicationContextHelper.applicationContext = applicationContext; 22 | } 23 | 24 | public static Object getBean(Class claz){ 25 | return ApplicationContextHelper.applicationContext.getBean(claz); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/listener/TheFlowEventType.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.flow.listener; 3 | 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | import java.util.Objects; 7 | 8 | /** 9 | * 特定流程事件类型 10 | */ 11 | public class TheFlowEventType { 12 | // 流程 13 | private String flow; 14 | // 类型 15 | private Class eventClass; 16 | 17 | public TheFlowEventType(String flow, Class eventClass) { 18 | this.flow = flow; 19 | this.eventClass = eventClass; 20 | } 21 | 22 | @Override 23 | public int hashCode() { 24 | return Objects.hash(flow, eventClass); 25 | } 26 | 27 | @Override 28 | public boolean equals(Object obj) { 29 | if (!(obj instanceof TheFlowEventType)) { 30 | return false; 31 | } 32 | TheFlowEventType other = (TheFlowEventType) obj; 33 | return StringUtils.equals(flow, other.flow) && eventClass == other.eventClass; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/Command.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | /** 4 | * Command stands for a request from Client. 5 | * According CommandExecutor will help to handle the business logic. This is a classic Command Pattern 6 | * 7 | * @author xujin 8 | */ 9 | public abstract class Command extends DTO{ 10 | 11 | private static final long serialVersionUID = 1L; 12 | 13 | /** 14 | * 不需要操作人设置此值为true 15 | */ 16 | private boolean operaterIsNotNeeded = false; 17 | 18 | /** 19 | * command的操作人 20 | */ 21 | private String operater; 22 | 23 | public String getOperater() { 24 | return operater; 25 | } 26 | 27 | public void setOperater(String operater) { 28 | this.operater = operater; 29 | } 30 | 31 | public boolean isOperaterIsNotNeeded() { 32 | return operaterIsNotNeeded; 33 | } 34 | 35 | public void setOperaterIsNotNeeded(boolean operaterIsNotNeeded) { 36 | this.operaterIsNotNeeded = operaterIsNotNeeded; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/event/NodeDecidedEvent.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.event; 2 | 3 | import org.xujin.halo.flow.engine.TargetContext; 4 | 5 | /** 6 | * 节点选择事件 7 | */ 8 | public class NodeDecidedEvent { 9 | // 流程名称 10 | private String flow; 11 | // 被选择的节点 12 | private String node; 13 | // 目标上下文 14 | private TargetContext targetContext; 15 | 16 | public NodeDecidedEvent(String flow, String node, TargetContext targetContext) { 17 | this.flow = flow; 18 | this.node = node; 19 | this.targetContext = targetContext; 20 | } 21 | 22 | /** 23 | * 获取流程名称 24 | */ 25 | public String getFlow() { 26 | return flow; 27 | } 28 | 29 | /** 30 | * 获取被选择的节点 31 | */ 32 | public String getNode() { 33 | return node; 34 | } 35 | 36 | /** 37 | * 获取目标上下文 38 | */ 39 | public TargetContext getTargetContext() { 40 | return targetContext; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /halo-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.xujin.halo 6 | halo 7 | 1.0.4 8 | ../pom.xml 9 | 10 | halo-common 11 | 1.0.4 12 | halo-common 13 | 14 | 15 | 16 | org.apache.maven.plugins 17 | maven-source-plugin 18 | 19 | 20 | attach-sources 21 | verify 22 | 23 | jar-no-fork 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/rule/RuleExecutor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.rule; 2 | 3 | import org.xujin.halo.extension.ExtensionExecutor; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * RuleExecutor 9 | * 10 | * Note that Rule is extensible as long as @Extension is added 11 | * 12 | * @author xujin 2017-11-04 13 | */ 14 | @Component 15 | public class RuleExecutor extends ExtensionExecutor { 16 | 17 | @Autowired 18 | private PlainRuleRepository plainRuleRepository; 19 | 20 | @Override 21 | protected C locateComponent(Class targetClz) { 22 | C rule = (C) plainRuleRepository.getPlainRules().get(targetClz); 23 | return null != rule ? rule : super.locateComponent(targetClz); 24 | } 25 | 26 | public void validate(Class targetClz, Object... candidate) { 27 | RuleI rule = this.locateComponent(targetClz); 28 | rule.validate(candidate); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/validator/ValidatorExecutor.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.validator; 3 | 4 | import org.xujin.halo.extension.ExtensionExecutor; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * ValidatorExecutor 10 | * 11 | * @author xujin 2017-11-04 12 | */ 13 | @Component 14 | public class ValidatorExecutor extends ExtensionExecutor { 15 | 16 | @Autowired 17 | private PlainValidatorRepository plainValidatorRepository; 18 | 19 | public void validate(Class targetClz, Object candidate) { 20 | ValidatorI validator = locateComponent(targetClz); 21 | validator.validate(candidate); 22 | } 23 | 24 | @Override 25 | protected C locateComponent(Class targetClz) { 26 | C validator = (C) plainValidatorRepository.getPlainValidators().get(targetClz); 27 | return null != validator ? validator : super.locateComponent(targetClz); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/pattern/filter/FilterChainFactory.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.pattern.filter; 2 | 3 | import org.xujin.halo.common.ApplicationContextHelper; 4 | 5 | /** 6 | * 责任链模式工厂 7 | * @author xujin 8 | * @date 2018/04/17 9 | */ 10 | public class FilterChainFactory { 11 | 12 | public static FilterChain buildFilterChain(Class... filterClsList) { 13 | FilterInvoker last = new FilterInvoker(){}; 14 | FilterChain filterChain = new FilterChain(); 15 | for(int i = filterClsList.length - 1; i >= 0; i--){ 16 | FilterInvoker next = last; 17 | Filter filter = (Filter)ApplicationContextHelper.getBean(filterClsList[i]); 18 | last = new FilterInvoker(){ 19 | @Override 20 | public void invoke(Object context) { 21 | filter.doFilter(context, next); 22 | } 23 | }; 24 | } 25 | filterChain.setHeader(last); 26 | return filterChain; 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/event/FlowExceptionEvent.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.event; 2 | 3 | import org.xujin.halo.flow.engine.TargetContext; 4 | 5 | /** 6 | * 流程异常事件 7 | */ 8 | public class FlowExceptionEvent { 9 | // 流程名称 10 | private String flow; 11 | // 发生的异常 12 | private Throwable throwable; 13 | // 目标上下文 14 | private TargetContext targetContext; 15 | 16 | public FlowExceptionEvent(String flow, Throwable throwable, TargetContext targetContext) { 17 | this.flow = flow; 18 | this.throwable = throwable; 19 | this.targetContext = targetContext; 20 | } 21 | 22 | /** 23 | * 获取流程名称 24 | */ 25 | public String getFlow() { 26 | return flow; 27 | } 28 | 29 | /** 30 | * 获取发生的异常 31 | */ 32 | public Throwable getThrowable() { 33 | return throwable; 34 | } 35 | 36 | /** 37 | * 获取目标上下文 38 | */ 39 | public TargetContext getTargetContext() { 40 | return targetContext; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/validator/extension/AddCustomerBizTwoValidator.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.validator.extension; 2 | 3 | import org.xujin.halo.exception.ParamException; 4 | import org.xujin.halo.extension.Extension; 5 | import org.xujin.halo.test.customer.AddCustomerCmd; 6 | import org.xujin.halo.test.customer.Constants; 7 | import org.xujin.halo.test.customer.validator.extensionpoint.AddCustomerValidatorExtPt; 8 | 9 | /** 10 | * AddCustomerBizTwoValidator 11 | * 12 | * @author xujin 13 | * @date 2018-01-07 1:31 AM 14 | */ 15 | @Extension(bizCode = Constants.BIZ_2) 16 | public class AddCustomerBizTwoValidator implements AddCustomerValidatorExtPt { 17 | 18 | @Override 19 | public void validate(Object candidate) { 20 | AddCustomerCmd addCustomerCmd = (AddCustomerCmd) candidate; 21 | //For BIZ TWO CustomerTYpe could not be null 22 | if (addCustomerCmd.getCustomerCO().getCustomerType() == null) 23 | throw new ParamException("CustomerType could not be null"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/logger/LoggerFactory.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.logger; 2 | 3 | public class LoggerFactory { 4 | 5 | private static boolean useSysLogger = true; 6 | 7 | public static Logger getLogger(Class clazz) { 8 | if(useSysLogger) { 9 | return SysLogger.singleton; 10 | } 11 | org.slf4j.Logger slfjLogger = org.slf4j.LoggerFactory.getLogger(clazz); 12 | return new SLFJLogger(slfjLogger); 13 | } 14 | 15 | public static Logger getLogger(String loggerName) { 16 | if(useSysLogger) { 17 | return SysLogger.singleton; 18 | } 19 | org.slf4j.Logger slfjLogger = org.slf4j.LoggerFactory.getLogger(loggerName); 20 | return new SLFJLogger(slfjLogger); 21 | } 22 | 23 | /** 24 | * This is just for test purpose, don't use it on product! 25 | */ 26 | public static void activateSysLogger() { 27 | useSysLogger = true; 28 | } 29 | 30 | public static void deactivateSysLogger() { 31 | useSysLogger = false; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/exception/BasicErrorCode.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.exception; 2 | 3 | /** 4 | * 5 | * 参数错误:1000 - 1999 6 | * 业务错误:2000 - 2999 7 | * 基础错误:3000 - 3999 8 | * 系统错误:4000 - 4999 9 | * 10 | * 基本的错误定义 11 | */ 12 | public enum BasicErrorCode implements ErrorCodeI{ 13 | PARAM_ERROR("1000" , "请求参数校验错误" , false), 14 | BIZ_ERROR("2000" , "业务逻辑错误" , false), 15 | INFRA_ERROR("3000" , "基础设施(数据库,缓存,消息等)错误" , true), 16 | SYS_ERROR("4000" , "未知的其它系统错误" , true); 17 | 18 | private String errCode; 19 | private String errDesc; 20 | private boolean retriable; 21 | 22 | private BasicErrorCode(String errCode, String errDesc, boolean retriable){ 23 | this.errCode = errCode; 24 | this.errDesc = errDesc; 25 | this.retriable = retriable; 26 | } 27 | 28 | @Override 29 | public String getErrCode() { 30 | return errCode; 31 | } 32 | 33 | @Override 34 | public String getErrDesc() { 35 | return errDesc; 36 | } 37 | 38 | @Override 39 | public boolean isRetriable() { 40 | return retriable; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/validator/extension/AddCustomerBizOneValidator.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.validator.extension; 2 | 3 | import org.xujin.halo.exception.BizException; 4 | import org.xujin.halo.extension.Extension; 5 | import org.xujin.halo.test.customer.AddCustomerCmd; 6 | import org.xujin.halo.test.customer.Constants; 7 | import org.xujin.halo.test.customer.CustomerType; 8 | import org.xujin.halo.test.customer.validator.extensionpoint.AddCustomerValidatorExtPt; 9 | 10 | /** 11 | * AddCustomerBizOneValidator 12 | * 13 | * @author xujin 14 | * @date 2018-01-07 1:31 AM 15 | */ 16 | @Extension(bizCode = Constants.BIZ_1) 17 | public class AddCustomerBizOneValidator implements AddCustomerValidatorExtPt { 18 | 19 | @Override 20 | public void validate(Object candidate) { 21 | AddCustomerCmd addCustomerCmd = (AddCustomerCmd) candidate; 22 | //For BIZ TWO CustomerTYpe could not be VIP 23 | if(CustomerType.VIP == addCustomerCmd.getCustomerCO().getCustomerType()) 24 | throw new BizException("Customer Type could not be VIP for Biz One"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/boot/EventBusConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.boot; 2 | 3 | import org.xujin.halo.event.EventPublisher; 4 | import org.xujin.halo.event.bus.EventBusesHolder; 5 | import org.xujin.halo.event.extension.support.BizListenerType; 6 | import org.xujin.halo.event.listener.ListenersHolder; 7 | import org.xujin.halo.event.publisher.DefaultEventPublisher; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.DependsOn; 11 | import org.springframework.context.annotation.Import; 12 | 13 | /** 14 | * 事件总线配置类 15 | * (非spring-boot项目需手动引入本配置类完成事件总线配置) 16 | */ 17 | @Configuration 18 | @Import({EventBusesHolder.class, ListenersHolder.class}) 19 | public class EventBusConfiguration { 20 | 21 | // 业务事件发布器 22 | @Bean 23 | @DependsOn("EventBusesHolder") // 保证出现循环引用时不会出错 24 | public EventPublisher eventPublisher(EventBusesHolder eventBusesHolder) { 25 | return new DefaultEventPublisher(eventBusesHolder.getEventBus(BizListenerType.class)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/extension/support/ClassListenResolver.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.extension.support; 2 | 3 | import org.xujin.halo.event.extension.ListenResolver; 4 | import org.springframework.util.ClassUtils; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * Class监听解决器(监听方法只能有一个入参,事件类型就是入参的Class类) 10 | */ 11 | public class ClassListenResolver implements ListenResolver { 12 | // 监听的事件类型 13 | private Class eventType; 14 | 15 | @Override 16 | public void init(Method listenMethod) { 17 | // 校验入参 18 | Class[] parameterTypes = listenMethod.getParameterTypes(); 19 | if (parameterTypes.length != 1) { 20 | throw new IllegalArgumentException(String.format("监听方法%s必须只有一个入参", ClassUtils.getQualifiedMethodName(listenMethod))); 21 | } 22 | // 设置事件类型 23 | eventType = parameterTypes[0]; 24 | } 25 | 26 | @Override 27 | public Object getEventType() { 28 | return eventType; 29 | } 30 | 31 | @Override 32 | public Object[] resolveArgs(Object event) { 33 | return new Object[]{event}; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/ClientObject.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | /** 8 | * This is the object communicate with Client. 9 | * The clients could be view layer or other RPC Consumers 10 | * @author xujin 2017-10-27 PM 12:19:15 11 | */ 12 | public abstract class ClientObject extends DTO implements Serializable{ 13 | 14 | private static final long serialVersionUID = 1L; 15 | 16 | /** 17 | * This is for extended values 18 | */ 19 | protected Map extValues = new HashMap(); 20 | 21 | public Object getExtField(String key){ 22 | if(extValues != null){ 23 | return extValues.get(key); 24 | } 25 | return null; 26 | } 27 | 28 | public void putExtField(String fieldName, Object value){ 29 | this.extValues.put(fieldName, value); 30 | } 31 | 32 | public Map getExtValues() { 33 | return extValues; 34 | } 35 | 36 | public void setExtValues(Map extValues) { 37 | this.extValues = extValues; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/SingleResponse.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | /** 4 | * Response with single record to return 5 | *

6 | * Created by xujin on 2018/6/1. 7 | */ 8 | 9 | public class SingleResponse extends Response { 10 | 11 | private T data; 12 | 13 | public static SingleResponse of(T data) { 14 | SingleResponse singleResponse = new SingleResponse<>(); 15 | singleResponse.setSuccess(true); 16 | singleResponse.setData(data); 17 | return singleResponse; 18 | } 19 | 20 | public T getData() { 21 | return data; 22 | } 23 | 24 | public void setData(T data) { 25 | this.data = data; 26 | } 27 | 28 | public static SingleResponse buildFailure(String errCode, String errMessage) { 29 | SingleResponse response = new SingleResponse(); 30 | response.setSuccess(false); 31 | response.setErrCode(errCode); 32 | response.setErrMessage(errMessage); 33 | return response; 34 | } 35 | 36 | public static SingleResponse buildSuccess(){ 37 | SingleResponse response = new SingleResponse(); 38 | response.setSuccess(true); 39 | return response; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/method/MethodExecutor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.method; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | 6 | /** 7 | * 方法执行器 8 | */ 9 | public abstract class MethodExecutor { 10 | // 目标方法 11 | private Method targetMethod; 12 | 13 | public MethodExecutor(Method targetMethod) { 14 | this.targetMethod = targetMethod; 15 | } 16 | 17 | /** 18 | * 执行方法 19 | * 20 | * @param obj 被执行的对象 21 | * @param args 需传入目标方法的参数 22 | * @return 目标方法返回的结果 23 | * @throws Throwable 执行过程中发生任何异常都会往外抛 24 | */ 25 | protected Object execute(Object obj, Object[] args) throws Throwable { 26 | try { 27 | return targetMethod.invoke(obj, args); 28 | } catch (InvocationTargetException e) { 29 | // 抛出原始异常 30 | throw e.getTargetException(); 31 | } 32 | } 33 | 34 | /** 35 | * 获取目标方法入参类型 36 | */ 37 | public Class[] getParameterTypes() { 38 | return targetMethod.getParameterTypes(); 39 | } 40 | 41 | /** 42 | * 获取目标方法返回类型 43 | */ 44 | public Class getReturnType() { 45 | return targetMethod.getReturnType(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/convertor/CustomerConvertor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.convertor; 2 | 3 | import org.xujin.halo.common.ApplicationContextHelper; 4 | import org.xujin.halo.convertor.ConvertorI; 5 | import org.xujin.halo.test.customer.CustomerCO; 6 | import org.xujin.halo.test.customer.entity.CustomerEntity; 7 | import org.springframework.beans.BeansException; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.context.ApplicationContextAware; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * CustomerConvertor 15 | * 16 | * @author xujin 17 | * @date 2018-01-07 3:08 AM 18 | */ 19 | @Component 20 | public class CustomerConvertor implements ConvertorI { 21 | 22 | public CustomerEntity clientToEntity(Object clientObject){ 23 | CustomerCO customerCO = (CustomerCO)clientObject; 24 | CustomerEntity customerEntity = (CustomerEntity)ApplicationContextHelper.getBean(CustomerEntity.class); 25 | customerEntity.setCompanyName(customerCO.getCompanyName()); 26 | customerEntity.setCustomerType(customerCO.getCustomerType()); 27 | return customerEntity; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /halo-collection/src/main/java/org/xujin/halo/domain/DomainUtils.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.domain; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 领域模型工具 9 | */ 10 | public class DomainUtils { 11 | /** 12 | * 生成领域模型图 13 | * @param packages 14 | */ 15 | public static void generationDomainGraph(String... packages){ 16 | AbilityCollection ac = new AbilityCollection(); 17 | Arrays.stream(packages).forEach(pkg -> { 18 | ac.addPackage(pkg); 19 | }); 20 | AbilityGraph ag = ac.collectAbility(); 21 | File file = new File("domain.dot"); 22 | try(FileOutputStream out = new FileOutputStream(file)){ 23 | file.createNewFile(); 24 | //写入dotsource 25 | out.write(ag.toString().getBytes()); 26 | //执行dot命令生成png图片 27 | Runtime rt = Runtime.getRuntime(); 28 | String[] param = {"dot", "-Tpng", "-o", "domain.png", "domain.dot"}; 29 | Process p = rt.exec(param); 30 | p.waitFor(); 31 | System.out.println("Runtime process finish:" + String.join(" ", param)); 32 | }catch(Exception e){ 33 | e.printStackTrace(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/PlainRuleRegister.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import org.xujin.halo.rule.PlainRuleRepository; 4 | import org.xujin.halo.rule.RuleI; 5 | import org.springframework.beans.BeansException; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.ApplicationContext; 8 | import org.springframework.context.ApplicationContextAware; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Plain Rule is Rule Component without ExtensionPoint 13 | * @author xujin 14 | * @date 2018/6/21 15 | */ 16 | @Component 17 | public class PlainRuleRegister implements RegisterI, ApplicationContextAware { 18 | 19 | @Autowired 20 | private PlainRuleRepository plainRuleRepository; 21 | 22 | private ApplicationContext applicationContext; 23 | 24 | @Override 25 | public void doRegistration(Class targetClz) { 26 | RuleI plainRule = (RuleI) applicationContext.getBean(targetClz); 27 | plainRuleRepository.getPlainRules().put(plainRule.getClass(), plainRule); 28 | } 29 | 30 | @Override 31 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 32 | this.applicationContext = applicationContext; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/EntityPrototypeTest.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test; 2 | 3 | import org.xujin.halo.TestConfig; 4 | import org.xujin.halo.common.ApplicationContextHelper; 5 | import org.xujin.halo.test.customer.entity.CustomerEntity; 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | 12 | /** 13 | * EntityPrototypeTest 14 | * 15 | * @author xujin 16 | * @date 2018-01-07 12:34 PM 17 | */ 18 | 19 | @RunWith(SpringRunner.class) 20 | @ContextConfiguration(classes = {TestConfig.class}) 21 | public class EntityPrototypeTest { 22 | 23 | @Test 24 | public void testPrototype(){ 25 | CustomerEntity customerEntity1 = (CustomerEntity)ApplicationContextHelper.getBean(CustomerEntity.class); 26 | System.out.println(customerEntity1); 27 | CustomerEntity customerEntity2 = (CustomerEntity)ApplicationContextHelper.getBean(CustomerEntity.class); 28 | System.out.println(customerEntity2); 29 | 30 | Assert.assertEquals(customerEntity1, customerEntity2); 31 | Assert.assertFalse(customerEntity1 == customerEntity2); //It should be different objects 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/boot/FlowEngineConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.boot; 2 | 3 | import org.xujin.halo.event.boot.EventBusConfiguration; 4 | import org.xujin.halo.flow.FlowEngine; 5 | import org.xujin.halo.flow.engine.DefaultFlowEngine; 6 | import org.xujin.halo.flow.flow.FlowsHolder; 7 | import org.xujin.halo.flow.listener.DefaultFlowListener; 8 | import org.xujin.halo.flow.processor.ProcessorsHolder; 9 | import org.xujin.halo.flow.transaction.FlowTxsHolder; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.context.annotation.DependsOn; 13 | import org.springframework.context.annotation.Import; 14 | 15 | /** 16 | * 流程引擎配置类 17 | * (非spring-boot项目需手动引入本配置类完成流程引擎配置) 18 | */ 19 | @Configuration 20 | @Import({EventBusConfiguration.class, 21 | FlowsHolder.class, 22 | ProcessorsHolder.class, 23 | FlowTxsHolder.class, 24 | DefaultFlowListener.class}) 25 | public class FlowEngineConfiguration { 26 | 27 | // 流程引擎 28 | @Bean 29 | @DependsOn({"FlowsHolder", "FlowTxsHolder"}) // 保证出现循环引用时不会出错 30 | public FlowEngine flowEngine(FlowsHolder flowsHolder, FlowTxsHolder flowTxsHolder) { 31 | return new DefaultFlowEngine(flowsHolder, flowTxsHolder); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/PlainValidatorRegister.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import org.xujin.halo.validator.PlainValidatorRepository; 4 | import org.xujin.halo.validator.ValidatorI; 5 | import org.springframework.beans.BeansException; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.ApplicationContext; 8 | import org.springframework.context.ApplicationContextAware; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Plain Validator is Validator Component without ExtensionPoint 13 | * @author xujin 14 | */ 15 | @Component 16 | public class PlainValidatorRegister implements RegisterI, ApplicationContextAware { 17 | 18 | @Autowired 19 | private PlainValidatorRepository plainValidatorRepository; 20 | 21 | private ApplicationContext applicationContext; 22 | 23 | @Override 24 | public void doRegistration(Class targetClz) { 25 | ValidatorI plainValidator= (ValidatorI) applicationContext.getBean(targetClz); 26 | plainValidatorRepository.getPlainValidators().put(plainValidator.getClass(), plainValidator); 27 | } 28 | 29 | @Override 30 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 31 | this.applicationContext = applicationContext; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/listener/TheFlowListenerType.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.listener; 2 | 3 | import org.xujin.halo.event.extension.EventTypeResolver; 4 | import org.xujin.halo.event.extension.ListenerType; 5 | import org.xujin.halo.flow.event.FlowExceptionEvent; 6 | import org.xujin.halo.flow.event.NodeDecidedEvent; 7 | 8 | /** 9 | * 特定流程监听器类型 10 | */ 11 | public class TheFlowListenerType implements ListenerType { 12 | 13 | @Override 14 | public EventTypeResolver getResolver() { 15 | return TheFlowEventTypeResolver.INSTANCE; 16 | } 17 | 18 | // 特定流程事件类型解决器 19 | private static class TheFlowEventTypeResolver implements EventTypeResolver { 20 | // 实例 21 | private static final TheFlowEventTypeResolver INSTANCE = new TheFlowEventTypeResolver(); 22 | 23 | @Override 24 | public Object resolve(Object event) { 25 | if (event instanceof NodeDecidedEvent) { 26 | return new TheFlowEventType(((NodeDecidedEvent) event).getFlow(), NodeDecidedEvent.class); 27 | } 28 | if (event instanceof FlowExceptionEvent) { 29 | return new TheFlowEventType(((FlowExceptionEvent) event).getFlow(), FlowExceptionEvent.class); 30 | } 31 | throw new IllegalArgumentException("无法识别的流程事件:" + event); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /halo-base/src/main/java/org/xujin/halo/domain/Entity.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.Date; 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | * 聚合内的实体 12 | * This is the parent object of all domain objects 13 | * @author xujin 14 | */ 15 | public abstract class Entity { 16 | 17 | /* 18 | * Entity 包含所有表都有的6个基础字段. 19 | */ 20 | @Getter @Setter 21 | protected String id; 22 | @Getter @Setter 23 | protected Date gmtCreate; 24 | @Getter @Setter 25 | protected Date gmtModified; 26 | @Getter @Setter 27 | protected String creator; 28 | @Getter @Setter 29 | protected String modifier; 30 | @Getter @Setter 31 | protected String isDeleted; 32 | @Getter @Setter 33 | protected String tenantId;//租户ID 34 | @Getter @Setter 35 | protected String bizCode;//业务代码 36 | 37 | /* 38 | * 扩展字段 39 | */ 40 | @Getter 41 | @Setter 42 | protected Map extValues = new ConcurrentHashMap(); 43 | 44 | public T getExtField(String key){ 45 | if(extValues != null){ 46 | return (T)extValues.get(key); 47 | } 48 | return null; 49 | } 50 | 51 | public void putExtField(String fieldName, Object value){ 52 | this.extValues.put(fieldName, value); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/convertor/CustomerBizTwoConvertorExt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.convertor; 2 | 3 | import org.xujin.halo.extension.Extension; 4 | import org.xujin.halo.test.customer.Constants; 5 | import org.xujin.halo.test.customer.CustomerCO; 6 | import org.xujin.halo.test.customer.entity.CustomerEntity; 7 | import org.xujin.halo.test.customer.entity.SourceType; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | /** 11 | * CustomerBizTwoConvertorExt 12 | * 13 | * @author xujin 14 | * @date 2018-01-07 3:05 AM 15 | */ 16 | @Extension(bizCode = Constants.BIZ_2) 17 | public class CustomerBizTwoConvertorExt implements CustomerConvertorExtPt{ 18 | 19 | @Autowired 20 | private CustomerConvertor customerConvertor;//Composite basic convertor to do basic conversion 21 | 22 | @Override 23 | public CustomerEntity clientToEntity(CustomerCO customerCO){ 24 | CustomerEntity customerEntity = customerConvertor.clientToEntity(customerCO); 25 | //In this business, if customers from RFQ and Advertisement are both regarded as Advertisement 26 | if(Constants.SOURCE_AD.equals(customerCO.getSource()) || Constants.SOURCE_RFQ.equals(customerCO.getSource())) 27 | { 28 | customerEntity.setSourceType(SourceType.AD); 29 | } 30 | return customerEntity; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/FlowEngine.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 流程引擎 7 | */ 8 | public interface FlowEngine { 9 | 10 | /** 11 | * 执行流程 12 | * 13 | * @param flow 流程名称 14 | * @param target 目标对象 15 | * @return 流程执行结束后的目标对象(可能和传入的目标对象不是同一个对象) 16 | */ 17 | T start(String flow, T target); 18 | 19 | /** 20 | * 执行流程 21 | * 22 | * @param flow 流程名称 23 | * @param target 目标对象 24 | * @param attachment 附件(为null的话则会自动生成一个空Map作为附件) 25 | * @return 流程执行结束后的目标对象(可能和传入的目标对象不是同一个对象) 26 | */ 27 | T start(String flow, T target, Map attachment); 28 | 29 | /** 30 | * 以新事务插入目标对象到数据库并提交事务 31 | * 32 | * @param flow 流程名称 33 | * @param target 目标对象 34 | * @param attachment 附件(为null的话则会自动生成一个空Map作为附件) 35 | * @return 插入到数据库后的目标对象(可能和传入的目标对象不是同一个对象) 36 | */ 37 | T insertTarget(String flow, T target, Map attachment); 38 | 39 | /** 40 | * 以新事务插入目标对象到数据库并提交事务,然后执行流程 41 | * 42 | * @param flow 流程名称 43 | * @param target 目标对象 44 | * @param attachment 附件(为null的话则会自动生成一个空Map作为附件) 45 | * @return 流程执行结束后的目标对象(可能和传入的目标对象不是同一个对象) 46 | */ 47 | T insertTargetAndStart(String flow, T target, Map attachment); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/listener/DefaultFlowListener.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.listener; 2 | 3 | import org.xujin.halo.event.EventPublisher; 4 | import org.xujin.halo.event.annotation.Listen; 5 | import org.xujin.halo.event.bus.EventBusesHolder; 6 | import org.xujin.halo.event.publisher.DefaultEventPublisher; 7 | import org.xujin.halo.flow.annotation.listener.FlowListener; 8 | import org.xujin.halo.flow.event.FlowExceptionEvent; 9 | import org.xujin.halo.flow.event.NodeDecidedEvent; 10 | import org.springframework.context.annotation.DependsOn; 11 | 12 | /** 13 | * 默认的流程监听器 14 | * (流程引擎初始化时会初始化本监听器,其作用是监听所有流程发生的事件,然后将事件转发给对应流程的特定流程监听器(@TheFlowListener)) 15 | */ 16 | @FlowListener 17 | @DependsOn("EventBusesHolder") // 保证出现循环引用时不会出错 18 | public class DefaultFlowListener { 19 | // 特定流程事件发布器 20 | private EventPublisher eventPublisher; 21 | 22 | public DefaultFlowListener(EventBusesHolder eventBusesHolder) { 23 | eventPublisher = new DefaultEventPublisher(eventBusesHolder.getEventBus(TheFlowListenerType.class)); 24 | } 25 | 26 | // 监听节点选择事件 27 | @Listen 28 | public void listenNodeDecidedEvent(NodeDecidedEvent event) { 29 | eventPublisher.publish(event); 30 | } 31 | 32 | // 监听流程异常事件 33 | @Listen 34 | public void listenFlowExceptionEvent(FlowExceptionEvent event) { 35 | eventPublisher.publish(event); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/engine/TargetContext.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.engine; 2 | 3 | import org.springframework.util.Assert; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * 目标上下文 10 | */ 11 | public class TargetContext { 12 | // 目标对象 13 | private T target; 14 | // 附件(一般存的是target不包含的信息,但在流程执行中又需要用到的信息) 15 | private Map attachment; 16 | 17 | public TargetContext(T target, Map attachment) { 18 | Assert.notNull(target, "目标对象不能为null"); 19 | this.target = target; 20 | this.attachment = attachment; 21 | if (this.attachment == null) { 22 | this.attachment = new HashMap<>(); 23 | } 24 | } 25 | 26 | /** 27 | * 获取目标对象 28 | */ 29 | public T getTarget() { 30 | return target; 31 | } 32 | 33 | /** 34 | * 刷新目标对象 35 | * 36 | * @param target 目标对象(会替换掉目标上下文中原有的目标对象) 37 | */ 38 | public void refreshTarget(T target) { 39 | Assert.notNull(target, "目标对象不能为null"); 40 | this.target = target; 41 | } 42 | 43 | /** 44 | * 获取附件属性 45 | */ 46 | public V getAttachmentAttr(Object key) { 47 | return (V) attachment.get(key); 48 | } 49 | 50 | /** 51 | * 设置附件属性 52 | */ 53 | public void setAttachmentAttr(Object key, Object value) { 54 | attachment.put(key, value); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/convertor/CustomerBizOneConvertorExt.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.convertor; 2 | 3 | import org.xujin.halo.extension.Extension; 4 | import org.xujin.halo.test.customer.Constants; 5 | import org.xujin.halo.test.customer.CustomerCO; 6 | import org.xujin.halo.test.customer.entity.CustomerEntity; 7 | import org.xujin.halo.test.customer.entity.SourceType; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | /** 11 | * CustomerBizOneConvertorExt 12 | * 13 | * @author xujin 14 | * @date 2018-01-07 3:05 AM 15 | */ 16 | @Extension(bizCode = Constants.BIZ_1) 17 | public class CustomerBizOneConvertorExt implements CustomerConvertorExtPt{ 18 | 19 | @Autowired 20 | private CustomerConvertor customerConvertor;//Composite basic convertor to do basic conversion 21 | 22 | @Override 23 | public CustomerEntity clientToEntity(CustomerCO customerCO){ 24 | CustomerEntity customerEntity = customerConvertor.clientToEntity(customerCO); 25 | //In this business, AD and RFQ are regarded as different source 26 | if(Constants.SOURCE_AD.equals(customerCO.getSource())) 27 | { 28 | customerEntity.setSourceType(SourceType.AD); 29 | } 30 | if (Constants.SOURCE_RFQ.equals(customerCO.getSource())){ 31 | customerEntity.setSourceType(SourceType.RFQ); 32 | } 33 | return customerEntity; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/PageQuery.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * page query 8 | *

9 | * Created by xujin on 2018/6/1. 10 | */ 11 | public abstract class PageQuery extends Query { 12 | 13 | private int pageNum = 1; 14 | private int pageSize = 10; 15 | private boolean needTotalCount = true; 16 | private List orderDescs; 17 | 18 | public int getPageNum() { 19 | return pageNum; 20 | } 21 | 22 | public void setPageNum(int pageNum) { 23 | this.pageNum = pageNum; 24 | } 25 | 26 | public int getPageSize() { 27 | return pageSize; 28 | } 29 | 30 | public void setPageSize(int pageSize) { 31 | this.pageSize = pageSize; 32 | } 33 | 34 | public boolean isNeedTotalCount() { 35 | return needTotalCount; 36 | } 37 | 38 | public void setNeedTotalCount(boolean needTotalCount) { 39 | this.needTotalCount = needTotalCount; 40 | } 41 | 42 | public List getOrderDescs() { 43 | return orderDescs; 44 | } 45 | 46 | public void addOrderDesc(OrderDesc orderDesc) { 47 | if (null == orderDescs) { 48 | orderDescs = new ArrayList<>(); 49 | } 50 | orderDescs.add(orderDesc); 51 | } 52 | 53 | public int getOffset() { 54 | return pageNum > 0 ? (pageNum - 1) * pageSize : 0; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/context/TenantContext.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.context; 2 | 3 | import org.xujin.halo.exception.BizException; 4 | 5 | /** 6 | * 租户的上下文 7 | */ 8 | public class TenantContext { 9 | 10 | private static ThreadLocal tenantContext = new ThreadLocal<>(); 11 | 12 | private static class Tenant{ 13 | String tenantId; 14 | String bizCode; 15 | private Tenant(String tenantId, String bizCode) { 16 | this.tenantId = tenantId; 17 | this.bizCode = bizCode; 18 | } 19 | } 20 | 21 | public static boolean exist(){ 22 | return null != tenantContext.get(); 23 | } 24 | 25 | public static String getTenantId() { 26 | if (tenantContext.get() == null || tenantContext.get().tenantId == null) { 27 | throw new BizException("No tenantId in Context"); 28 | } 29 | return tenantContext.get().tenantId; 30 | } 31 | 32 | public static String getBizCode() { 33 | if (tenantContext.get() == null || tenantContext.get().bizCode == null) { 34 | throw new BizException("No bizCode in Context"); 35 | } 36 | return tenantContext.get().bizCode; 37 | } 38 | 39 | public static void set(String tenantId, String bizCode) { 40 | Tenant tenant = new Tenant(tenantId, bizCode); 41 | tenantContext.set(tenant); 42 | } 43 | 44 | public static void remove() { 45 | tenantContext.remove(); 46 | } 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/validator/ValidatorCompoiste.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.validator; 2 | 3 | import com.google.common.collect.Lists; 4 | import org.springframework.beans.factory.InitializingBean; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 使用组合模式,允许一个Validator可以组合多个其它的Validator完成validation的任务 10 | * 11 | * @author xujin 2017-11-04 12 | */ 13 | 14 | public abstract class ValidatorCompoiste implements ValidatorI, InitializingBean { 15 | 16 | private List validators; 17 | 18 | /** 19 | * Composite other validators if necessary 20 | */ 21 | abstract protected void addOtherValidators(); 22 | 23 | /** 24 | * Aside from composited validators, do its own validation here 25 | * @param candidate 26 | */ 27 | abstract protected void doValidate(Object candidate); 28 | 29 | protected void add(ValidatorI validator) { 30 | if (validators == null) { 31 | validators = Lists.newArrayList(); 32 | } 33 | validators.add(validator); 34 | } 35 | 36 | @Override 37 | public void validate(Object candidate) { 38 | if (validators != null) { 39 | for (ValidatorI validator : validators) { 40 | validator.validate(candidate); 41 | } 42 | } 43 | doValidate(candidate); 44 | } 45 | 46 | @Override 47 | public void afterPropertiesSet() throws Exception { 48 | addOtherValidators(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /halo-test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.xujin.halo 6 | halo 7 | 1.0.4 8 | ../pom.xml 9 | 10 | halo-test 11 | 1.0.4 12 | halo-test 13 | 14 | 15 | junit 16 | junit 17 | compile 18 | 19 | 20 | org.springframework 21 | spring-core 22 | 23 | 24 | org.springframework 25 | spring-context 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-source-plugin 35 | 36 | 37 | attach-sources 38 | verify 39 | 40 | jar-no-fork 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/interceptor/ValidationInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.interceptor; 2 | 3 | import org.xujin.halo.command.CommandInterceptorI; 4 | import org.xujin.halo.command.PreInterceptor; 5 | import org.xujin.halo.dto.Command; 6 | import org.xujin.halo.exception.ParamException; 7 | import org.xujin.halo.validator.HaloMessageInterpolator; 8 | import org.hibernate.validator.HibernateValidator; 9 | 10 | import javax.validation.ConstraintViolation; 11 | import javax.validation.Validation; 12 | import javax.validation.Validator; 13 | import javax.validation.ValidatorFactory; 14 | import java.util.Set; 15 | 16 | /** 17 | * ValidationInterceptor 18 | * 19 | * @author xujin 2018-01-06 8:27 PM 20 | */ 21 | @PreInterceptor 22 | public class ValidationInterceptor implements CommandInterceptorI { 23 | 24 | //Enable fail fast, which will improve performance 25 | private ValidatorFactory factory = Validation.byProvider(HibernateValidator.class).configure().failFast(true) 26 | .messageInterpolator(new HaloMessageInterpolator()).buildValidatorFactory(); 27 | 28 | @Override 29 | public void preIntercept(Command command) { 30 | Validator validator = factory.getValidator(); 31 | Set> constraintViolations = validator.validate(command); 32 | constraintViolations.forEach(violation -> { 33 | throw new ParamException(violation.getPropertyPath() + " " + violation.getMessage()); 34 | }); 35 | } 36 | } -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/entity/CustomerEntity.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer.entity; 2 | 3 | import org.xujin.halo.domain.Entity; 4 | import org.xujin.halo.extension.ExtensionExecutor; 5 | import org.xujin.halo.test.customer.CustomerType; 6 | import org.xujin.halo.test.customer.entity.rule.CustomerRuleExtPt; 7 | import org.xujin.halo.test.customer.repository.CustomerRepository; 8 | import lombok.Data; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.config.ConfigurableBeanFactory; 11 | import org.springframework.context.annotation.Scope; 12 | import org.springframework.stereotype.Component; 13 | 14 | /** 15 | * Customer Entity 16 | * 17 | * @author xujin 18 | * @date 2018-01-07 2:38 AM 19 | */ 20 | @Data 21 | @Component 22 | @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) 23 | public class CustomerEntity extends Entity { 24 | 25 | private String companyName; 26 | private SourceType sourceType; 27 | private CustomerType customerType; 28 | 29 | @Autowired 30 | private CustomerRepository customerRepository; 31 | @Autowired 32 | private ExtensionExecutor extensionExecutor; 33 | 34 | public CustomerEntity() { 35 | 36 | } 37 | 38 | public void addNewCustomer() { 39 | //Add customer policy 40 | extensionExecutor.execute(CustomerRuleExtPt.class, extension -> extension.addCustomerCheck(this)); 41 | 42 | //Persist customer 43 | customerRepository.persist(this); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /halo-utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | org.xujin.halo 7 | halo 8 | 1.0.4 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | halo-utils 14 | 1.0.4 15 | halo-utils 16 | 17 | 18 | 19 | 20 | 21 | ma.glasnost.orika 22 | orika-core 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-source-plugin 32 | 33 | 34 | attach-sources 35 | verify 36 | 37 | jar-no-fork 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /halo-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | halo 7 | org.xujin.halo 8 | 1.0.4 9 | 10 | 4.0.0 11 | halo-starter 12 | halo-starter 13 | 14 | 15 | 16 | org.xujin.halo 17 | halo-utils 18 | 19 | 20 | org.xujin.halo 21 | halo-core 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-autoconfigure 27 | provided 28 | true 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-source-plugin 39 | 3.0.1 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /halo-event/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.xujin.halo 9 | halo 10 | 1.0.4 11 | ../pom.xml 12 | 13 | 14 | halo-event 15 | halo-event 16 | 17 | 18 | 19 | org.xujin.halo 20 | halo-common 21 | ${project.parent.version} 22 | 23 | 24 | org.springframework 25 | spring-context 26 | provided 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-autoconfigure 31 | provided 32 | true 33 | 34 | 35 | org.slf4j 36 | slf4j-api 37 | 38 | 39 | org.apache.commons 40 | commons-lang3 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/bus/EventBusesHolder.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.bus; 2 | 3 | import org.xujin.halo.event.extension.ListenerType; 4 | import org.xujin.halo.event.listener.ListenerExecutor; 5 | import org.xujin.halo.event.listener.ListenerParser; 6 | import org.xujin.halo.event.listener.ListenersHolder; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.annotation.PostConstruct; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * 事件总线持有器 16 | */ 17 | @Component 18 | public class EventBusesHolder { 19 | @Autowired 20 | private ListenersHolder listenersHolder; 21 | // 事件总线Map(key:总线类型) 22 | private Map eventBusMap = new HashMap<>(); 23 | 24 | // 初始化(根据监听器类型创建相应类型的事件总线,spring自动执行) 25 | @PostConstruct 26 | public void init() { 27 | for (Class type : listenersHolder.getTypes()) { 28 | // 初始化事件总线 29 | EventBus eventBus = getEventBus(type); 30 | for (ListenerExecutor listenerExecutor : listenersHolder.getRequiredListenerExecutors(type)) { 31 | eventBus.register(listenerExecutor); 32 | } 33 | } 34 | } 35 | 36 | /** 37 | * 获取事件总线 38 | * (如果不存在该类型的事件总线,则新创建一个) 39 | * 40 | * @param type 总线类型 41 | */ 42 | public synchronized EventBus getEventBus(Class type) { 43 | if (!eventBusMap.containsKey(type)) { 44 | eventBusMap.put(type, new EventBus(ListenerParser.parseEventTypeResolver(type))); 45 | } 46 | return eventBusMap.get(type); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/Response.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | /** 4 | * Response to caller 5 | * 6 | * @author xujin 2017年10月21日 下午8:53:17 7 | */ 8 | public class Response extends DTO{ 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private boolean isSuccess; 13 | 14 | private String errCode; 15 | 16 | private String errMessage; 17 | 18 | public boolean isSuccess() { 19 | return isSuccess; 20 | } 21 | 22 | 23 | public void setSuccess(boolean isSuccess) { 24 | this.isSuccess = isSuccess; 25 | } 26 | 27 | 28 | public String getErrCode() { 29 | return errCode; 30 | } 31 | 32 | 33 | public void setErrCode(String errCode) { 34 | this.errCode = errCode; 35 | } 36 | 37 | 38 | public String getErrMessage() { 39 | return errMessage; 40 | } 41 | 42 | 43 | public void setErrMessage(String errMessage) { 44 | this.errMessage = errMessage; 45 | } 46 | 47 | 48 | @Override 49 | public String toString() { 50 | return "Response [isSuccess=" + isSuccess + ", errCode=" + errCode + ", errMessage=" + errMessage + "]"; 51 | } 52 | 53 | public static Response buildFailure(String errCode, String errMessage) { 54 | Response response = new Response(); 55 | response.setSuccess(false); 56 | response.setErrCode(errCode); 57 | response.setErrMessage(errMessage); 58 | return response; 59 | } 60 | 61 | public static Response buildSuccess(){ 62 | Response response = new Response(); 63 | response.setSuccess(true); 64 | return response; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 1.Halo Framework 2 | 3 | Halo, 发音美 [ˈheɪloʊ],和hello发音基本一致,中文名光环。Halo是Hallo的简写,是德语你好的意思。 4 | Halo框架名寓意是赋能于业务应用开发,业务方使用者自带光环,脚踏七彩祥云,为业务开发造福,为业务架构治理和防腐提供统一的方法论。 5 | Halo框架是基于CQRS+扩展点+流程编排的应用框架,致力于采用领域驱动的设计思想,规范控制程序员的随心所欲,从而解决软件的复杂性问题。 6 | 架构原则很简单,即在高内聚,低耦合,可扩展,易理解大的指导思想下,尽可能的贯彻OO的设计思想和原则。 7 | 8 | 如果你觉得Halo不错,让你很爽,烦请拨冗**“Star”**。 9 | 10 | 11 | > Halo Framework,光环框架是基于DDD+CQRS+扩展点+业务中间件,业务系统使用之自带光环! 12 | 13 | > Halo,中文名光环。美 [ˈheɪloʊ],Halo是Hallo的简写,是德语你好的意思。 14 | 15 | ## 2.Halo 模块 16 | 17 | | 模块名 | 描述 | 备注 | 18 | | --- | --- | --- | 19 | | halo-base | base层注解 | | 20 | | halo-collection | 采集能力图 | | 21 | | halo-common | 框架公共部分 | | 22 | | halo-core | 框架核心 | | 23 | | halo-event | 框架Event事件 | | 24 | | halo-flow | 流程编排 | todo 待重构 | 25 | | halo-test | 框架测试模块 | todo 待重构 | 26 | | halo-utils | 框架工具类用于各种DTO对象之间快速复制 | | 27 | | halo-springcloud | 分布式Command |第二种结合Spring Cloud | 28 | 29 | ## 3.使用 30 | 31 | ### 3.1 maven 依赖 32 | 33 | ```pom 34 | 1.0.4 35 | 36 | 37 | 38 | org.xujin.halo 39 | halo-core 40 | ${halo.framework.version} 41 | 42 | 43 | 44 | 45 | org.xujin.halo 46 | halo-test 47 | ${halo.framework.version} 48 | test 49 | 50 | 51 | 52 | 53 | 54 | org.xujin.halo 55 | halo-collection 56 | ${halo.framework.version} 57 | 58 | ``` 59 | 60 | 案例:[crm-sales](https://github.com/SoftwareKing/crm-sales) 61 | 62 | 63 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/event/EventHub.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event; 2 | 3 | import org.xujin.halo.dto.event.Event; 4 | import org.xujin.halo.exception.InfraException; 5 | import com.google.common.collect.ArrayListMultimap; 6 | import com.google.common.collect.ListMultimap; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * 事件控制中枢 17 | * @author xujin 18 | * @date 2018/5/20 19 | */ 20 | @SuppressWarnings("rawtypes") 21 | @Component 22 | public class EventHub { 23 | @Getter 24 | @Setter 25 | private ListMultimap eventRepository = ArrayListMultimap.create(); 26 | 27 | @Getter 28 | private Map responseRepository = new HashMap<>(); 29 | 30 | public List getEventHandler(Class eventClass) { 31 | List eventHandlerIList = findHandler(eventClass); 32 | if (eventHandlerIList == null || eventHandlerIList.size() == 0) { 33 | throw new InfraException(eventClass + "is not registered in eventHub, please register first"); 34 | } 35 | return eventHandlerIList; 36 | } 37 | 38 | /** 39 | * 注册事件 40 | * @param eventClz 41 | * @param executor 42 | */ 43 | public void register(Class eventClz, EventHandlerI executor){ 44 | eventRepository.put(eventClz, executor); 45 | } 46 | 47 | private List findHandler(Class eventClass){ 48 | List eventHandlerIList = null; 49 | Class cls = eventClass; 50 | eventHandlerIList = eventRepository.get(cls); 51 | return eventHandlerIList; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /halo-flow/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.xujin.halo 8 | halo 9 | 1.0.4 10 | 11 | 12 | halo-flow 13 | halo-flow 14 | 15 | 16 | 17 | org.xujin.halo 18 | halo-common 19 | ${project.parent.version} 20 | 21 | 22 | org.xujin.halo 23 | halo-event 24 | ${project.parent.version} 25 | 26 | 27 | org.springframework 28 | spring-context 29 | provided 30 | 31 | 32 | org.springframework 33 | spring-tx 34 | provided 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-autoconfigure 39 | provided 40 | true 41 | 42 | 43 | org.apache.commons 44 | commons-lang3 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /halo-common/src/main/java/org/xujin/halo/dto/MultiResponse.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.dto; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.List; 6 | 7 | /** 8 | * Response with batch record to return, 9 | * usually use in page query or conditional query 10 | *

11 | * Created by xujin on 2018/6/1. 12 | */ 13 | public class MultiResponse extends Response { 14 | 15 | private int total; 16 | 17 | private Collection data; 18 | 19 | public static MultiResponse of(Collection data, int total) { 20 | MultiResponse multiResponse = new MultiResponse<>(); 21 | multiResponse.setSuccess(true); 22 | multiResponse.setData(data); 23 | multiResponse.setTotal(total); 24 | return multiResponse; 25 | } 26 | 27 | public static MultiResponse ofWithoutTotal(Collection data) { 28 | return of(data,0); 29 | } 30 | 31 | 32 | public int getTotal() { 33 | return total; 34 | } 35 | 36 | 37 | public void setTotal(int total) { 38 | this.total = total; 39 | } 40 | 41 | public List getData() { 42 | return null == data ? new ArrayList<>() : new ArrayList<>(data); 43 | } 44 | 45 | 46 | public void setData(Collection data) { 47 | this.data = data; 48 | } 49 | 50 | public static MultiResponse buildFailure(String errCode, String errMessage) { 51 | MultiResponse response = new MultiResponse(); 52 | response.setSuccess(false); 53 | response.setErrCode(errCode); 54 | response.setErrMessage(errMessage); 55 | return response; 56 | } 57 | 58 | public static MultiResponse buildSuccess(){ 59 | MultiResponse response = new MultiResponse(); 60 | response.setSuccess(true); 61 | return response; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /halo-core/src/test/java/org/xujin/halo/test/customer/AddCustomerCmdExe.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.test.customer; 2 | 3 | import org.xujin.halo.command.Command; 4 | import org.xujin.halo.command.CommandExecutorI; 5 | import org.xujin.halo.dto.Response; 6 | import org.xujin.halo.extension.ExtensionExecutor; 7 | import org.xujin.halo.logger.Logger; 8 | import org.xujin.halo.logger.LoggerFactory; 9 | import org.xujin.halo.test.customer.convertor.CustomerConvertorExtPt; 10 | import org.xujin.halo.test.customer.entity.CustomerEntity; 11 | import org.xujin.halo.test.customer.validator.extensionpoint.AddCustomerValidatorExtPt; 12 | import org.xujin.halo.validator.ValidatorExecutor; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | 15 | /** 16 | * AddCustomerCmdExe 17 | * 18 | * @author xujin 2018-01-06 7:48 PM 19 | */ 20 | @Command 21 | public class AddCustomerCmdExe implements CommandExecutorI { 22 | 23 | private Logger logger = LoggerFactory.getLogger(AddCustomerCmd.class); 24 | 25 | @Autowired 26 | private ValidatorExecutor validatorExecutor; 27 | 28 | @Autowired 29 | private ExtensionExecutor extensionExecutor; 30 | 31 | 32 | @Override 33 | public Response execute(AddCustomerCmd cmd) { 34 | logger.info("Start processing command:" + cmd); 35 | validatorExecutor.validate(AddCustomerValidatorExtPt.class, cmd); 36 | 37 | //Convert CO to Entity 38 | CustomerEntity customerEntity = extensionExecutor.execute(CustomerConvertorExtPt.class, extension -> extension.clientToEntity(cmd.getCustomerCO())); 39 | 40 | //Call Domain Entity for business logic processing 41 | logger.info("Call Domain Entity for business logic processing..."+customerEntity); 42 | customerEntity.addNewCustomer(); 43 | 44 | logger.info("End processing command:" + cmd); 45 | return Response.buildSuccess(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/CommandHub.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.xujin.halo.exception.InfraException; 4 | import com.google.common.collect.LinkedListMultimap; 5 | import com.google.common.collect.ListMultimap; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.util.ArrayList; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * Command Hub holds all the important information about Command 17 | * 18 | * @author xujin 19 | */ 20 | @SuppressWarnings("rawtypes") 21 | @Component 22 | public class CommandHub{ 23 | 24 | @Getter 25 | @Setter 26 | private ListMultimap preInterceptors = LinkedListMultimap.create(); 27 | @Getter 28 | @Setter 29 | private ListMultimap postInterceptors = LinkedListMultimap.create(); 30 | 31 | @Getter 32 | @Setter 33 | //全局通用的PreInterceptors 34 | private List globalPreInterceptors = new ArrayList<>(); 35 | @Getter 36 | @Setter 37 | //全局通用的PostInterceptors 38 | private List globalPostInterceptors = new ArrayList<>(); 39 | @Getter 40 | @Setter 41 | private Map commandRepository = new HashMap<>(); 42 | 43 | @Getter 44 | private Map responseRepository = new HashMap<>(); 45 | 46 | public CommandInvocation getCommandInvocation(Class cmdClass) { 47 | CommandInvocation commandInvocation = commandRepository.get(cmdClass); 48 | if (commandRepository.get(cmdClass) == null){ 49 | throw new InfraException(cmdClass + " is not registered in CommandHub, please register first"); 50 | } 51 | return commandInvocation; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/Bootstrap.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | import java.util.TreeSet; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | 9 | import org.xujin.halo.exception.InfraException; 10 | 11 | import lombok.Getter; 12 | import lombok.Setter; 13 | 14 | /** 15 | * 应用的核心引导启动类 16 | *

17 | * 负责扫描在applicationContext.xml中配置的packages. 获取到CommandExecutors, intercepters, extensions, validators等 18 | * 交给各个注册器进行注册。 19 | * 20 | * @author xujin 2017-11-04 21 | */ 22 | public class Bootstrap { 23 | @Getter 24 | @Setter 25 | private List packages; 26 | private ClassPathScanHandler handler; 27 | 28 | @Autowired 29 | private RegisterFactory registerFactory; 30 | 31 | 32 | public void init() { 33 | Set> classSet = scanConfiguredPackages(); 34 | registerBeans(classSet); 35 | } 36 | 37 | /** 38 | * @param classSet 39 | */ 40 | private void registerBeans(Set> classSet) { 41 | for (Class targetClz : classSet) { 42 | RegisterI register = registerFactory.getRegister(targetClz); 43 | if (null != register) { 44 | register.doRegistration(targetClz); 45 | } 46 | } 47 | 48 | } 49 | 50 | /** 51 | * Scan the packages configured in Spring xml 52 | * 53 | * @return 54 | */ 55 | private Set> scanConfiguredPackages() { 56 | if (packages == null) throw new InfraException("Command packages is not specified"); 57 | 58 | String[] pkgs = new String[packages.size()]; 59 | handler = new ClassPathScanHandler(packages.toArray(pkgs)); 60 | 61 | Set> classSet = new TreeSet<>(new ClassNameComparator()); 62 | for (String pakName : packages) { 63 | classSet.addAll(handler.getPackageAllClasses(pakName, true)); 64 | } 65 | return classSet; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/CommandInvocation.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.xujin.halo.dto.Command; 4 | import org.xujin.halo.dto.Response; 5 | import com.google.common.collect.FluentIterable; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | public class CommandInvocation { 11 | 12 | @Setter 13 | private CommandExecutorI commandExecutor; 14 | @Setter 15 | private Iterable preInterceptors; 16 | @Setter 17 | private Iterable postInterceptors; 18 | 19 | public CommandInvocation() { 20 | 21 | } 22 | 23 | public CommandInvocation(CommandExecutorI commandExecutor, List preInterceptors, 24 | List postInterceptors){ 25 | this.commandExecutor = commandExecutor; 26 | this.preInterceptors = preInterceptors; 27 | this.postInterceptors = postInterceptors; 28 | } 29 | 30 | public R invoke(C command) { 31 | R response = null; 32 | try { 33 | preIntercept(command); 34 | response = commandExecutor.execute(command); 35 | response.setSuccess(true); 36 | } 37 | finally { 38 | //make sure post interceptors performs even though exception happens 39 | postIntercept(command, response); 40 | } 41 | return response; 42 | } 43 | 44 | private void postIntercept(C command, R response) { 45 | for (CommandInterceptorI postInterceptor : FluentIterable.from(postInterceptors).toSet()) { 46 | postInterceptor.postIntercept(command, response); 47 | } 48 | } 49 | 50 | private void preIntercept(C command) { 51 | for (CommandInterceptorI preInterceptor : FluentIterable.from(preInterceptors).toSet()) { 52 | preInterceptor.preIntercept(command); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/PreInterceptorRegister.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.boot; 3 | 4 | import org.xujin.halo.command.CommandHub; 5 | import org.xujin.halo.command.CommandInterceptorI; 6 | import org.xujin.halo.command.PreInterceptor; 7 | import org.xujin.halo.dto.Command; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.ApplicationContext; 11 | import org.springframework.context.ApplicationContextAware; 12 | import org.springframework.stereotype.Component; 13 | 14 | /** 15 | * PreInterceptorRegister 16 | * @author xujin 17 | */ 18 | @Component 19 | public class PreInterceptorRegister extends AbstractRegister implements ApplicationContextAware{ 20 | 21 | @Autowired 22 | private CommandHub commandHub; 23 | 24 | @Override 25 | public void doRegistration(Class targetClz) { 26 | CommandInterceptorI commandInterceptor = getBean(targetClz); 27 | PreInterceptor preInterceptorAnn = targetClz.getDeclaredAnnotation(PreInterceptor.class); 28 | Class[] supportClasses = preInterceptorAnn.commands(); 29 | registerInterceptor(supportClasses, commandInterceptor); 30 | } 31 | 32 | private void registerInterceptor(Class[] supportClasses, CommandInterceptorI commandInterceptor) { 33 | if (null == supportClasses || supportClasses.length == 0) { 34 | commandHub.getGlobalPreInterceptors().add(commandInterceptor); 35 | order(commandHub.getGlobalPreInterceptors()); 36 | return; 37 | } 38 | for (Class supportClass : supportClasses) { 39 | commandHub.getPreInterceptors().put(supportClass, commandInterceptor); 40 | order(commandHub.getPreInterceptors().get(supportClass)); 41 | } 42 | } 43 | 44 | @Override 45 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 46 | this.applicationContext = applicationContext; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/listener/ListenNodeDecidedResolver.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.listener; 2 | 3 | import org.xujin.halo.event.extension.ListenResolver; 4 | import org.xujin.halo.flow.annotation.listener.TheFlowListener; 5 | import org.xujin.halo.flow.engine.TargetContext; 6 | import org.xujin.halo.flow.event.NodeDecidedEvent; 7 | import org.springframework.core.annotation.AnnotatedElementUtils; 8 | import org.springframework.util.ClassUtils; 9 | 10 | import java.lang.reflect.Method; 11 | 12 | /** 13 | * 监听注解@ListenNodeDecided的解决器 14 | */ 15 | public class ListenNodeDecidedResolver implements ListenResolver { 16 | // 监听的事件类型 17 | private TheFlowEventType eventType; 18 | 19 | @Override 20 | public void init(Method listenMethod) { 21 | TheFlowListener theFlowListenerAnnotation = AnnotatedElementUtils.findMergedAnnotation(listenMethod.getDeclaringClass(), TheFlowListener.class); 22 | if (theFlowListenerAnnotation == null) { 23 | throw new IllegalArgumentException("@ListenNodeDecided只能标注在特定流程监听器(@TheFlowListener)的方法上"); 24 | } 25 | // 校验入参 26 | Class[] parameterTypes = listenMethod.getParameterTypes(); 27 | if (parameterTypes.length != 2) { 28 | throw new RuntimeException("监听节点选择方法" + ClassUtils.getQualifiedMethodName(listenMethod) + "的入参必须是(String, TargetContext)"); 29 | } 30 | if (parameterTypes[0] != String.class || parameterTypes[1] != TargetContext.class) { 31 | throw new RuntimeException("监听节点选择方法" + ClassUtils.getQualifiedMethodName(listenMethod) + "的入参必须是(String, TargetContext)"); 32 | } 33 | eventType = new TheFlowEventType(theFlowListenerAnnotation.flow(), NodeDecidedEvent.class); 34 | } 35 | 36 | @Override 37 | public Object getEventType() { 38 | return eventType; 39 | } 40 | 41 | @Override 42 | public Object[] resolveArgs(Object event) { 43 | NodeDecidedEvent nodeDecidedEvent = (NodeDecidedEvent) event; 44 | return new Object[]{nodeDecidedEvent.getNode(), nodeDecidedEvent.getTargetContext()}; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /halo-collection/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | org.xujin.halo 7 | halo 8 | 1.0.4 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | halo-collection 14 | 15 | halo-collection 16 | 17 | 18 | 19 | 20 | org.xujin.halo 21 | halo-base 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | 27 | 28 | org.springframework 29 | spring-core 30 | 31 | 32 | org.springframework 33 | spring-context 34 | 35 | 36 | 37 | org.reflections 38 | reflections 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-source-plugin 47 | 48 | 49 | attach-sources 50 | verify 51 | 52 | jar-no-fork 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/PostInterceptorRegister.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.boot; 3 | 4 | import org.xujin.halo.command.CommandHub; 5 | import org.xujin.halo.command.CommandInterceptorI; 6 | import org.xujin.halo.command.PostInterceptor; 7 | import org.xujin.halo.dto.Command; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.ApplicationContext; 11 | import org.springframework.context.ApplicationContextAware; 12 | import org.springframework.stereotype.Component; 13 | 14 | /** 15 | * PostInterceptorRegister 16 | * @author xujin 17 | */ 18 | @Component 19 | public class PostInterceptorRegister extends AbstractRegister implements ApplicationContextAware{ 20 | 21 | @Autowired 22 | private CommandHub commandHub; 23 | 24 | @Override 25 | public void doRegistration(Class targetClz) { 26 | CommandInterceptorI commandInterceptor = getBean(targetClz); 27 | PostInterceptor postInterceptorAnn = targetClz.getDeclaredAnnotation(PostInterceptor.class); 28 | Class[] supportClasses = postInterceptorAnn.commands(); 29 | registerInterceptor(supportClasses, commandInterceptor); 30 | } 31 | 32 | private void registerInterceptor(Class[] supportClasses, CommandInterceptorI commandInterceptor) { 33 | if (null == supportClasses || supportClasses.length == 0) { 34 | commandHub.getGlobalPostInterceptors().add(commandInterceptor); 35 | order(commandHub.getGlobalPostInterceptors()); 36 | return; 37 | } 38 | for (Class supportClass : supportClasses) { 39 | commandHub.getPostInterceptors().put(supportClass, commandInterceptor); 40 | order(commandHub.getPostInterceptors().get(supportClass)); 41 | } 42 | } 43 | 44 | @Override 45 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 46 | this.applicationContext = applicationContext; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /halo-base/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | org.xujin.halo 7 | halo 8 | 1.0.4 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | halo-base 14 | 1.0.4 15 | halo-base 16 | 17 | 18 | 19 | 20 | org.xujin.halo 21 | halo-common 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | 27 | 28 | org.springframework 29 | spring-core 30 | 31 | 32 | org.springframework 33 | spring-context 34 | 35 | 36 | 37 | org.reflections 38 | reflections 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-source-plugin 47 | 48 | 49 | attach-sources 50 | verify 51 | 52 | jar-no-fork 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/listener/ListenFlowExceptionResolver.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.listener; 2 | 3 | import org.xujin.halo.event.extension.ListenResolver; 4 | import org.xujin.halo.flow.annotation.listener.TheFlowListener; 5 | import org.xujin.halo.flow.engine.TargetContext; 6 | import org.xujin.halo.flow.event.FlowExceptionEvent; 7 | import org.springframework.core.annotation.AnnotatedElementUtils; 8 | import org.springframework.util.ClassUtils; 9 | 10 | import java.lang.reflect.Method; 11 | 12 | /** 13 | * 监听注解@ListenFlowException的解决器 14 | */ 15 | public class ListenFlowExceptionResolver implements ListenResolver { 16 | // 监听的事件类型 17 | private TheFlowEventType eventType; 18 | 19 | @Override 20 | public void init(Method listenMethod) { 21 | TheFlowListener theFlowListenerAnnotation = AnnotatedElementUtils.findMergedAnnotation(listenMethod.getDeclaringClass(), TheFlowListener.class); 22 | if (theFlowListenerAnnotation == null) { 23 | throw new IllegalArgumentException("@ListenFlowException只能标注在特定流程监听器(@TheFlowListener)的方法上"); 24 | } 25 | // 校验入参 26 | Class[] parameterTypes = listenMethod.getParameterTypes(); 27 | if (parameterTypes.length != 2) { 28 | throw new RuntimeException("监听流程异常方法" + ClassUtils.getQualifiedMethodName(listenMethod) + "的入参必须是(Throwable, TargetContext)"); 29 | } 30 | if (parameterTypes[0] != Throwable.class || parameterTypes[1] != TargetContext.class) { 31 | throw new RuntimeException("监听流程异常方法" + ClassUtils.getQualifiedMethodName(listenMethod) + "的入参必须是(Throwable, TargetContext)"); 32 | } 33 | eventType = new TheFlowEventType(theFlowListenerAnnotation.flow(), FlowExceptionEvent.class); 34 | } 35 | 36 | @Override 37 | public Object getEventType() { 38 | return eventType; 39 | } 40 | 41 | @Override 42 | public Object[] resolveArgs(Object event) { 43 | FlowExceptionEvent flowExceptionEvent = (FlowExceptionEvent) event; 44 | return new Object[]{flowExceptionEvent.getThrowable(), flowExceptionEvent.getTargetContext()}; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/processor/ProcessorsHolder.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.processor; 2 | 3 | import org.xujin.halo.flow.annotation.processor.Processor; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.stereotype.Component; 7 | 8 | import javax.annotation.PostConstruct; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | /** 14 | * 处理器持有器 15 | */ 16 | @Component 17 | public class ProcessorsHolder { 18 | @Autowired 19 | private ApplicationContext applicationContext; 20 | // 处理器执行器Map(key:处理器的名称) 21 | private Map processorExecutorMap = new HashMap<>(); 22 | 23 | // 初始化(查询spring容器中所有的@Processor处理器并解析,spring自动执行) 24 | @PostConstruct 25 | public void init() { 26 | String[] beanNames = applicationContext.getBeanNamesForAnnotation(Processor.class); 27 | for (String beanName : beanNames) { 28 | // 解析处理器 29 | ProcessorExecutor processorExecutor = ProcessorParser.parseProcessor(applicationContext.getBean(beanName)); 30 | if (processorExecutorMap.containsKey(processorExecutor.getProcessorName())) { 31 | throw new RuntimeException("存在重名的处理器:" + processorExecutor.getProcessorName()); 32 | } 33 | // 将执行器放入持有器中 34 | processorExecutorMap.put(processorExecutor.getProcessorName(), processorExecutor); 35 | } 36 | } 37 | 38 | /** 39 | * 获取所有处理器名称 40 | */ 41 | public Set getProcessorNames() { 42 | return processorExecutorMap.keySet(); 43 | } 44 | 45 | /** 46 | * 获取处理器执行器 47 | * 48 | * @param processor 处理器名称 49 | * @throws IllegalArgumentException 如果不存在该处理器执行器 50 | */ 51 | public ProcessorExecutor getRequiredProcessorExecutor(String processor) { 52 | if (!processorExecutorMap.containsKey(processor)) { 53 | throw new IllegalArgumentException("不存在处理器:" + processor); 54 | } 55 | return processorExecutorMap.get(processor); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/context/PvgContext.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.context; 2 | 3 | import org.xujin.halo.exception.Preconditions; 4 | 5 | /** 6 | * Pvg Context 7 | *

8 | * Created by xujin on 2018/4/9. 9 | */ 10 | public class PvgContext { 11 | 12 | private static ThreadLocal pvgContext = new ThreadLocal<>(); 13 | 14 | private static class Pvg { 15 | private String crmUserId; 16 | private String roleName; 17 | private String orgId; 18 | private String corpId; 19 | 20 | public Pvg(String crmUserId, String roleName, String orgId, String corpId) { 21 | this.crmUserId = crmUserId; 22 | this.roleName = roleName; 23 | this.orgId = orgId; 24 | this.corpId = corpId; 25 | } 26 | } 27 | 28 | public static void set(String crmUserId, String roleName, String orgId, String corpId) { 29 | Pvg pvg = new Pvg(crmUserId, roleName, orgId, corpId); 30 | pvgContext.set(pvg); 31 | } 32 | 33 | public static void remove() { 34 | pvgContext.remove(); 35 | } 36 | 37 | public static boolean exist() { 38 | return null != pvgContext.get(); 39 | } 40 | 41 | public static String getCrmUserId() { 42 | Preconditions.checkArgument(null != pvgContext.get() && null != pvgContext.get().crmUserId, 43 | "No User in Context"); 44 | return pvgContext.get().crmUserId; 45 | } 46 | 47 | public static String getRoleName() { 48 | Preconditions.checkArgument(null != pvgContext.get() && null != pvgContext.get().roleName, 49 | "No roleName in Context"); 50 | return pvgContext.get().roleName; 51 | } 52 | 53 | public static String getOrgId() { 54 | Preconditions.checkArgument(null != pvgContext.get() && null != pvgContext.get().orgId, 55 | "No orgId in Context"); 56 | return pvgContext.get().orgId; 57 | } 58 | 59 | public static String getCorpId() { 60 | Preconditions.checkArgument(null != pvgContext.get() && null != pvgContext.get().corpId, 61 | "No corpId in Context"); 62 | return pvgContext.get().corpId; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/listener/ListenersHolder.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.listener; 2 | 3 | import org.xujin.halo.event.annotation.listener.Listener; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.util.ClassUtils; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.*; 11 | 12 | /** 13 | * 监听器持有器 14 | */ 15 | @Component 16 | public class ListenersHolder { 17 | @Autowired 18 | private ApplicationContext applicationContext; 19 | // 监听器执行器Map(key:监听器的类型) 20 | private Map> listenerExecutorsMap = new HashMap<>(); 21 | 22 | // 初始化(查询spring容器中所有的@Listener监听器并解析,spring自动执行) 23 | @PostConstruct 24 | public void init() { 25 | String[] beanNames = applicationContext.getBeanNamesForAnnotation(Listener.class); 26 | for (String beanName : beanNames) { 27 | // 解析监听器 28 | ListenerExecutor listenerExecutor = ListenerParser.parseListener(applicationContext.getBean(beanName)); 29 | // 将执行器放入持有器中 30 | List listenerExecutors = listenerExecutorsMap.get(listenerExecutor.getType()); 31 | if (listenerExecutors == null) { 32 | listenerExecutors = new ArrayList<>(); 33 | listenerExecutorsMap.put(listenerExecutor.getType(), listenerExecutors); 34 | } 35 | listenerExecutors.add(listenerExecutor); 36 | } 37 | } 38 | 39 | /** 40 | * 获取所有的监听器类型 41 | */ 42 | public Set getTypes() { 43 | return listenerExecutorsMap.keySet(); 44 | } 45 | 46 | /** 47 | * 获取指定类型的监听器执行器 48 | * 49 | * @param type 监听器类型 50 | * @throws IllegalArgumentException 如果不存在该类型的监听器执行器 51 | */ 52 | public List getRequiredListenerExecutors(Class type) { 53 | if (!listenerExecutorsMap.containsKey(type)) { 54 | throw new IllegalArgumentException("不存在" + ClassUtils.getShortName(type) + "类型的监听器"); 55 | } 56 | return listenerExecutorsMap.get(type); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/extension/ExtensionCoordinate.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.extension; 2 | 3 | import lombok.Data; 4 | import org.apache.commons.lang3.builder.ToStringBuilder; 5 | import org.apache.commons.lang3.builder.ToStringStyle; 6 | 7 | /** 8 | * Extension Coordinate(扩展点坐标) used to uniquely position a Extension 9 | * @author xujin 10 | */ 11 | @Data 12 | public class ExtensionCoordinate { 13 | 14 | private String extensionPoint; 15 | private String bizCode; 16 | private String tenantId; 17 | 18 | /** 19 | * @param extensionPoint 20 | * @param bizCode 21 | * @param tenantId 22 | */ 23 | public ExtensionCoordinate(String extensionPoint, String bizCode, String tenantId){ 24 | super(); 25 | this.extensionPoint = extensionPoint; 26 | this.bizCode = bizCode; 27 | this.tenantId = tenantId; 28 | } 29 | 30 | @Override 31 | public int hashCode() { 32 | final int prime = 31; 33 | int result = 1; 34 | result = prime * result + ((bizCode == null) ? 0 : bizCode.hashCode()); 35 | result = prime * result + ((extensionPoint == null) ? 0 : extensionPoint.hashCode()); 36 | result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode()); 37 | return result; 38 | } 39 | @Override 40 | public boolean equals(Object obj) { 41 | if (this == obj) return true; 42 | if (obj == null) return false; 43 | if (getClass() != obj.getClass()) return false; 44 | ExtensionCoordinate other = (ExtensionCoordinate) obj; 45 | if (bizCode == null) { 46 | if (other.bizCode != null) return false; 47 | } else if (!bizCode.equals(other.bizCode)) return false; 48 | if (extensionPoint == null) { 49 | if (other.extensionPoint != null) return false; 50 | } else if (!extensionPoint.equals(other.extensionPoint)) return false; 51 | if (tenantId == null) { 52 | if (other.tenantId != null) return false; 53 | } else if (!tenantId.equals(other.tenantId)) return false; 54 | return true; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/logger/Logger.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.logger; 2 | 3 | /** 4 | * This is a typical DIP, by depending on ourselves logger, we can change the underline logger vendor easily 5 | * 6 | * @author xujin 2017年10月23日 下午11:58:54 7 | */ 8 | public interface Logger { 9 | 10 | /** 11 | * Log a message at the DEBUG level. 12 | * 13 | * @param msg the message string to be logged 14 | */ 15 | public void debug(String msg); 16 | 17 | /** 18 | * Log a message at the DEBUG level. support format. 19 | * 20 | * @param msg 21 | * @param args 22 | */ 23 | default public void debug(String msg, Object... args){ 24 | debug(String.format(msg, args)); 25 | } 26 | 27 | /** 28 | * Log a message at the INFO level. 29 | * 30 | * @param msg the message string to be logged 31 | */ 32 | public void info(String msg); 33 | 34 | /** 35 | * Log a message at the INFO level. support format. 36 | * 37 | * @param msg 38 | * @param args 39 | */ 40 | default public void info(String msg, Object... args){ 41 | info(String.format(msg, args)); 42 | } 43 | 44 | /** 45 | * Log a message at the WARN level. 46 | * 47 | * @param msg the message string to be logged 48 | */ 49 | public void warn(String msg); 50 | 51 | /** 52 | * Log a message at the WARN level. support format. 53 | * 54 | * @param msg 55 | * @param args 56 | */ 57 | default public void warn(String msg, Object... args){ 58 | warn(String.format(msg, args)); 59 | } 60 | /** 61 | * Log a message at the ERROR level. 62 | * 63 | * @param msg the message string to be logged 64 | */ 65 | public void error(String msg); 66 | 67 | /** 68 | * Log a message at the ERROR level. support format. 69 | * @param msg 70 | * @param args 71 | */ 72 | default public void error(String msg, Object... args){ 73 | error(String.format(msg, args)); 74 | } 75 | 76 | /** 77 | * Log an exception (throwable) at the ERROR level with an 78 | * accompanying message. 79 | * 80 | * @param msg the message accompanying the exception 81 | * @param t the exception (throwable) to log 82 | */ 83 | public void error(String msg, Throwable t); 84 | } 85 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/transaction/TxExecutor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.transaction; 2 | 3 | import org.springframework.transaction.PlatformTransactionManager; 4 | import org.springframework.transaction.TransactionDefinition; 5 | import org.springframework.transaction.TransactionStatus; 6 | import org.springframework.transaction.support.DefaultTransactionDefinition; 7 | 8 | /** 9 | * 事务执行器 10 | */ 11 | public class TxExecutor { 12 | // 事务定义(传播行为是REQUIRES_NEW,即每次都开启一个新事务) 13 | private static final TransactionDefinition TX_DEFINITION = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW); 14 | 15 | // 事务管理器 16 | private PlatformTransactionManager transactionManager; 17 | // 事务持有器 18 | private ThreadLocal txStatusHolder = new ThreadLocal<>(); 19 | 20 | public TxExecutor(PlatformTransactionManager transactionManager) { 21 | this.transactionManager = transactionManager; 22 | } 23 | 24 | /** 25 | * 创建事务 26 | * 27 | * @throws IllegalStateException 如果已存在事务 28 | */ 29 | public void createTx() { 30 | if (txStatusHolder.get() != null) { 31 | throw new IllegalStateException("本线程事务已存在,不能同时创建多个事务"); 32 | } 33 | txStatusHolder.set(transactionManager.getTransaction(TX_DEFINITION)); 34 | } 35 | 36 | /** 37 | * 提交事务 38 | * 39 | * @throws IllegalStateException 如果不存在事务 40 | */ 41 | public void commitTx() { 42 | if (txStatusHolder.get() == null) { 43 | throw new IllegalStateException("事务不存在,无法提交事务"); 44 | } 45 | transactionManager.commit(txStatusHolder.get()); 46 | txStatusHolder.remove(); 47 | } 48 | 49 | /** 50 | * 回滚事务 51 | * 52 | * @throws IllegalStateException 如果不存在事务 53 | */ 54 | public void rollbackTx() { 55 | if (txStatusHolder.get() == null) { 56 | throw new IllegalStateException("事务不存在,无法回滚事务"); 57 | } 58 | transactionManager.rollback(txStatusHolder.get()); 59 | txStatusHolder.remove(); 60 | } 61 | 62 | /** 63 | * 校验事务执行器是否有效 64 | * 65 | * @throws IllegalStateException 如果校验不通过 66 | */ 67 | public void validate() { 68 | if (transactionManager == null) { 69 | throw new IllegalStateException("事务执行器内部要素不全"); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/EventRegister.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import org.xujin.halo.common.CoreConstant; 4 | import org.xujin.halo.dto.event.Event; 5 | import org.xujin.halo.event.EventHandlerI; 6 | import org.xujin.halo.event.EventHub; 7 | import org.xujin.halo.exception.InfraException; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.ApplicationContext; 11 | import org.springframework.context.ApplicationContextAware; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.lang.reflect.Method; 15 | 16 | /** 17 | * EventRegister 18 | * 19 | * @author xujin 20 | * @date 2018/3/20 21 | */ 22 | @SuppressWarnings({ "rawtypes", "unchecked" }) 23 | @Component 24 | public class EventRegister extends AbstractRegister implements ApplicationContextAware { 25 | 26 | @Autowired 27 | private EventHub eventHub; 28 | 29 | @Override 30 | public void doRegistration(Class targetClz) { 31 | Class eventClz = getEventFromExecutor(targetClz); 32 | EventHandlerI executor = getBean(targetClz); 33 | eventHub.register(eventClz, executor); 34 | } 35 | 36 | private Class getEventFromExecutor(Class eventExecutorClz) { 37 | Method[] methods = eventExecutorClz.getDeclaredMethods(); 38 | for (Method method : methods) { 39 | Class[] exeParams = method.getParameterTypes(); 40 | /** 41 | * This is for return right response type on exception scenarios 42 | */ 43 | if (CoreConstant.EXE_METHOD.equals(method.getName()) && exeParams.length == 1 44 | && Event.class.isAssignableFrom(exeParams[0]) && !method.isBridge()) { 45 | eventHub.getResponseRepository().put(eventExecutorClz, method.getReturnType()); 46 | return (Class) exeParams[0]; 47 | } 48 | } 49 | throw new InfraException("Event param in " + eventExecutorClz + " " + CoreConstant.EXE_METHOD 50 | + "() is not detected"); 51 | } 52 | 53 | @Override 54 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 55 | this.applicationContext = applicationContext; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/flow/FlowsHolder.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.flow; 2 | 3 | import org.xujin.halo.event.bus.EventBusesHolder; 4 | import org.xujin.halo.flow.annotation.flow.Flow; 5 | import org.xujin.halo.flow.processor.ProcessorsHolder; 6 | import org.xujin.halo.flow.transaction.FlowTxsHolder; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.ApplicationContext; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.annotation.PostConstruct; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | /** 17 | * 流程持有器 18 | */ 19 | @Component 20 | public class FlowsHolder { 21 | @Autowired 22 | private ApplicationContext applicationContext; 23 | @Autowired 24 | private ProcessorsHolder processorsHolder; 25 | @Autowired 26 | private FlowTxsHolder flowTxsHolder; 27 | @Autowired 28 | private EventBusesHolder eventBusesHolder; 29 | // 流程执行器Map(key:流程名称) 30 | private Map flowExecutorMap = new HashMap<>(); 31 | 32 | // 初始化(查询spring容器中所有的@Flow流程并解析,spring自动执行) 33 | @PostConstruct 34 | public void init() { 35 | String[] beanNames = applicationContext.getBeanNamesForAnnotation(Flow.class); 36 | for (String beanName : beanNames) { 37 | // 解析流程 38 | FlowExecutor flowExecutor = FlowParser.parseFlow(applicationContext.getBean(beanName), processorsHolder, flowTxsHolder, eventBusesHolder); 39 | if (flowExecutorMap.containsKey(flowExecutor.getFlowName())) { 40 | throw new RuntimeException("存在重名的流程" + flowExecutor.getFlowName()); 41 | } 42 | // 将执行器放入持有器中 43 | flowExecutorMap.put(flowExecutor.getFlowName(), flowExecutor); 44 | } 45 | } 46 | 47 | /** 48 | * 获取所有流程名称 49 | */ 50 | public Set getFlowNames() { 51 | return flowExecutorMap.keySet(); 52 | } 53 | 54 | /** 55 | * 获取流程执行器 56 | * 57 | * @param flow 流程名称 58 | * @throws IllegalArgumentException 如果不存在该流程执行器 59 | */ 60 | public FlowExecutor getRequiredFlowExecutor(String flow) { 61 | if (!flowExecutorMap.containsKey(flow)) { 62 | throw new IllegalArgumentException("不存在流程" + flow); 63 | } 64 | return flowExecutorMap.get(flow); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/transaction/FlowTxsHolder.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.transaction; 2 | 3 | import org.xujin.halo.flow.annotation.transaction.FlowTx; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.transaction.PlatformTransactionManager; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | /** 15 | * 流程事务持有器 16 | */ 17 | @Component 18 | public class FlowTxsHolder { 19 | @Autowired 20 | private ApplicationContext applicationContext; 21 | @Autowired(required = false) 22 | private PlatformTransactionManager transactionManager; 23 | // 流程事务执行器Map(key:流程事务对应的流程名称) 24 | private Map flowTxExecutorMap = new HashMap<>(); 25 | 26 | // 初始化(查询spring容器中所有的@FlowTx流程事务并解析,spring自动执行) 27 | @PostConstruct 28 | public void init() { 29 | String[] beanNames = applicationContext.getBeanNamesForAnnotation(FlowTx.class); 30 | if (beanNames.length > 0 && transactionManager == null) { 31 | throw new RuntimeException("存在流程事务但是不存在事务管理器(PlatformTransactionManager),请检查是否有配置spring事务管理器"); 32 | } 33 | for (String beanName : beanNames) { 34 | // 解析流程事务 35 | FlowTxExecutor flowTxExecutor = FlowTxParser.parseFlowTx(applicationContext.getBean(beanName), transactionManager); 36 | if (flowTxExecutorMap.containsKey(flowTxExecutor.getFlow())) { 37 | throw new RuntimeException("流程" + flowTxExecutor.getFlow() + "存在多个流程事务"); 38 | } 39 | // 将执行器放入持有器中 40 | flowTxExecutorMap.put(flowTxExecutor.getFlow(), flowTxExecutor); 41 | } 42 | } 43 | 44 | /** 45 | * 获取所有流程事务对应的流程名称 46 | */ 47 | public Set getFlowNames() { 48 | return flowTxExecutorMap.keySet(); 49 | } 50 | 51 | /** 52 | * 获取流程事务执行器 53 | * 54 | * @param flow 流程名称 55 | * @throws IllegalArgumentException 如果不存在该流程事务处理器 56 | */ 57 | public FlowTxExecutor getRequiredFlowTxExecutor(String flow) { 58 | if (!flowTxExecutorMap.containsKey(flow)) { 59 | throw new IllegalArgumentException("不存在流程" + flow + "的流程事务"); 60 | } 61 | return flowTxExecutorMap.get(flow); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/command/CommandBus.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.command; 2 | 3 | import org.xujin.halo.exception.BasicErrorCode; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | import org.xujin.halo.context.TenantContext; 8 | import org.xujin.halo.dto.Command; 9 | import org.xujin.halo.dto.Response; 10 | import org.xujin.halo.exception.HaloException; 11 | import org.xujin.halo.exception.ErrorCodeI; 12 | import org.xujin.halo.exception.InfraException; 13 | import org.xujin.halo.logger.Logger; 14 | import org.xujin.halo.logger.LoggerFactory; 15 | 16 | /** 17 | * Just send Command to CommandBus, 18 | * 19 | * @author xujin 2017年10月24日 上午12:47:18 20 | */ 21 | @Component 22 | public class CommandBus implements CommandBusI{ 23 | 24 | Logger logger = LoggerFactory.getLogger(CommandBus.class); 25 | 26 | @Autowired 27 | private CommandHub commandHub; 28 | 29 | @SuppressWarnings("unchecked") 30 | @Override 31 | public Response send(Command cmd) { 32 | Response response = null; 33 | try { 34 | //从commandHub中获取到对应的命令去调用命令的execute方法 35 | response = commandHub.getCommandInvocation(cmd.getClass()).invoke(cmd); 36 | } 37 | catch (Exception exception) { 38 | //统一的Command异常处理器 39 | response = handleException(cmd, response, exception); 40 | } 41 | finally { 42 | //Clean up context 43 | TenantContext.remove(); 44 | } 45 | return response; 46 | } 47 | 48 | private Response handleException(Command cmd, Response response, Exception exception) { 49 | logger.error(exception.getMessage(), exception); 50 | Class responseClz = commandHub.getResponseRepository().get(cmd.getClass()); 51 | try { 52 | response = (Response) responseClz.newInstance(); 53 | } catch (Exception e) { 54 | logger.error(e.getMessage(), e); 55 | throw new InfraException(e.getMessage()); 56 | } 57 | if (exception instanceof HaloException) { 58 | ErrorCodeI errCode = ((HaloException) exception).getErrCode(); 59 | response.setErrCode(errCode.getErrCode()); 60 | } 61 | else { 62 | response.setErrCode(BasicErrorCode.SYS_ERROR.getErrCode()); 63 | } 64 | response.setErrMessage(exception.getMessage()); 65 | return response; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/AbstractRegister.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import org.xujin.halo.exception.InfraException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.core.Ordered; 6 | import org.springframework.core.annotation.Order; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author xujin 12 | * @date 2018/02/13 13 | */ 14 | public abstract class AbstractRegister implements RegisterI{ 15 | 16 | protected ApplicationContext applicationContext; 17 | 18 | protected T getBean(Class targetClz){ 19 | T executorI = null; 20 | //优先按type查 21 | try { 22 | executorI = (T) applicationContext.getBean(targetClz); 23 | }catch (Exception e){ 24 | } 25 | //按name查 26 | if(executorI == null){ 27 | String simpleName = targetClz.getSimpleName(); 28 | //首字母小写 29 | simpleName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1); 30 | executorI = (T) applicationContext.getBean(simpleName); 31 | } 32 | if(executorI == null){ 33 | new InfraException("Command " + targetClz + " init error!"); 34 | } 35 | return executorI; 36 | } 37 | 38 | /** 39 | * 根据Order注解排序 40 | * @param interceptorIList 41 | */ 42 | protected void order(List interceptorIList){ 43 | if(interceptorIList == null || interceptorIList.size() <= 1){ 44 | return; 45 | } 46 | T newInterceptor = interceptorIList.get(interceptorIList.size() - 1); 47 | Order order = newInterceptor.getClass().getDeclaredAnnotation(Order.class); 48 | if(order == null){ 49 | return; 50 | } 51 | int index = interceptorIList.size() - 1; 52 | for(int i = interceptorIList.size() - 2; i >= 0; i--){ 53 | int itemOrderInt = Ordered.LOWEST_PRECEDENCE; 54 | Order itemOrder = interceptorIList.get(i).getClass().getDeclaredAnnotation(Order.class); 55 | if(itemOrder != null){ 56 | itemOrderInt = itemOrder.value(); 57 | } 58 | if(itemOrderInt > order.value()){ 59 | interceptorIList.set(index, interceptorIList.get(i)); 60 | index = i; 61 | }else { 62 | break; 63 | } 64 | } 65 | if(index < interceptorIList.size() - 1){ 66 | interceptorIList.set(index, newInterceptor); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/extension/ExtensionExecutor.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.extension; 2 | 3 | import org.xujin.halo.boot.ComponentExecutor; 4 | import org.xujin.halo.common.CoreConstant; 5 | import org.xujin.halo.common.DefaultBizCode; 6 | import org.xujin.halo.context.TenantContext; 7 | import org.xujin.halo.exception.InfraException; 8 | import org.xujin.halo.logger.Logger; 9 | import org.xujin.halo.logger.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * 扩展点执行器-ExtensionExecutor 15 | * @author xujin 16 | */ 17 | @Component 18 | public class ExtensionExecutor extends ComponentExecutor{ 19 | 20 | private Logger logger = LoggerFactory.getLogger(ExtensionExecutor.class); 21 | 22 | @Autowired 23 | private ExtensionRepository extensionRepository; 24 | 25 | @Override 26 | protected C locateComponent(Class targetClz) { 27 | C extension = locateExtension(targetClz); 28 | logger.debug("[Located Extension]: "+extension.getClass().getSimpleName()); 29 | return locateExtension(targetClz); 30 | } 31 | 32 | /** 33 | * @param targetClz 34 | */ 35 | @SuppressWarnings("unchecked") 36 | protected Ext locateExtension(Class targetClz) { 37 | String bizCode = TenantContext.getBizCode(); 38 | String tenantId = TenantContext.getTenantId(); 39 | ExtensionCoordinate extensionCoordinate = new ExtensionCoordinate(targetClz.getSimpleName(), bizCode, tenantId); 40 | /** 41 | * 1.First search key is: extensionPoint + bizCode + tenantId 42 | */ 43 | Ext extension = (Ext)extensionRepository.getExtensionRepo().get(extensionCoordinate); 44 | if (extension != null) { 45 | return extension; 46 | } 47 | /** 48 | * 2.Second search key is: extensionPoint + bizCode 49 | */ 50 | extensionCoordinate.setTenantId(CoreConstant.DEFAULT_TENANT_ID); 51 | extension = (Ext)extensionRepository.getExtensionRepo().get(extensionCoordinate); 52 | if (extension != null) { 53 | return extension; 54 | } 55 | /** 56 | * 3.Third search key is: extensionPoint 57 | */ 58 | extensionCoordinate.setBizCode(DefaultBizCode.DEFAULT_BIZ_CODE); 59 | extension = (Ext)extensionRepository.getExtensionRepo().get(extensionCoordinate); 60 | if (extension != null) { 61 | return extension; 62 | } 63 | throw new InfraException("Can not find extension for ExtensionPoint: "+targetClz); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /halo-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.xujin.halo 7 | halo 8 | 1.0.4 9 | ../pom.xml 10 | 11 | halo-core 12 | 1.0.4 13 | halo-core 14 | 15 | 16 | 17 | org.xujin.halo 18 | halo-base 19 | 20 | 21 | 22 | org.projectlombok 23 | lombok 24 | 25 | 26 | org.springframework 27 | spring-core 28 | 29 | 30 | org.springframework 31 | spring-context 32 | 33 | 34 | org.slf4j 35 | slf4j-api 36 | 37 | 38 | org.reflections 39 | reflections 40 | 41 | 42 | org.apache.commons 43 | commons-lang3 44 | 45 | 46 | 47 | org.hibernate.validator 48 | hibernate-validator 49 | 50 | 51 | javax.el 52 | javax.el-api 53 | test 54 | 55 | 56 | org.glassfish.web 57 | javax.el 58 | test 59 | 60 | 61 | 62 | junit 63 | junit 64 | test 65 | 66 | 67 | org.springframework 68 | spring-test 69 | test 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-source-plugin 78 | 79 | 80 | attach-sources 81 | verify 82 | 83 | jar-no-fork 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/ExtensionRegister.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.boot; 2 | 3 | import org.xujin.halo.common.CoreConstant; 4 | import org.xujin.halo.exception.InfraException; 5 | import org.xujin.halo.extension.Extension; 6 | import org.xujin.halo.extension.ExtensionCoordinate; 7 | import org.xujin.halo.extension.ExtensionPointI; 8 | import org.xujin.halo.extension.ExtensionRepository; 9 | import org.apache.commons.lang3.ArrayUtils; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.springframework.beans.BeansException; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.context.ApplicationContext; 14 | import org.springframework.context.ApplicationContextAware; 15 | import org.springframework.stereotype.Component; 16 | 17 | /** 18 | * ExtensionRegister 19 | * @author xujin 20 | */ 21 | @Component 22 | public class ExtensionRegister implements RegisterI, ApplicationContextAware{ 23 | 24 | @Autowired 25 | private ExtensionRepository extensionRepository; 26 | 27 | private ApplicationContext applicationContext; 28 | 29 | @Override 30 | public void doRegistration(Class targetClz) { 31 | ExtensionPointI extension = (ExtensionPointI) applicationContext.getBean(targetClz); 32 | Extension extensionAnn = targetClz.getDeclaredAnnotation(Extension.class); 33 | String extensionPoint = calculateExtensionPoint(targetClz); 34 | ExtensionCoordinate extensionCoordinate = new ExtensionCoordinate(extensionPoint, extensionAnn.bizCode(), extensionAnn.tenantId()); 35 | ExtensionPointI preVal = extensionRepository.getExtensionRepo().put(extensionCoordinate, extension); 36 | if (preVal != null) { 37 | throw new InfraException("Duplicate registration is not allowed for :"+extensionCoordinate); 38 | } 39 | } 40 | 41 | /** 42 | * @param targetClz 43 | * @return 44 | */ 45 | private String calculateExtensionPoint(Class targetClz) { 46 | Class[] interfaces = targetClz.getInterfaces(); 47 | if (ArrayUtils.isEmpty(interfaces)) 48 | throw new InfraException("Please assign a extension point interface for "+targetClz); 49 | for (Class intf : interfaces) { 50 | String extensionPoint = intf.getSimpleName(); 51 | if (StringUtils.contains(extensionPoint, CoreConstant.EXTENSION_EXTPT_NAMING)) 52 | return extensionPoint; 53 | } 54 | throw new InfraException("Your name of ExtensionPoint for "+targetClz+" is not valid, must be end of "+CoreConstant.EXTENSION_EXTPT_NAMING); 55 | } 56 | 57 | 58 | 59 | @Override 60 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 61 | this.applicationContext = applicationContext; 62 | } 63 | } -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/bus/EventBus.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.bus; 2 | 3 | import org.xujin.halo.event.extension.EventTypeResolver; 4 | import org.xujin.halo.event.listener.ListenerExecutor; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * 事件总线 10 | */ 11 | public class EventBus { 12 | // 监听器执行器 13 | private List listenerExecutors = new ArrayList<>(); 14 | // 监听器执行器缓存(key:事件类型) 15 | private Map> listenerExecutorsCache = new HashMap<>(); 16 | // 事件类型解决器 17 | private EventTypeResolver resolver; 18 | 19 | public EventBus(EventTypeResolver resolver) { 20 | this.resolver = resolver; 21 | } 22 | 23 | /** 24 | * 注册监听器 25 | * 26 | * @param listenerExecutor 监听器执行器 27 | */ 28 | public void register(ListenerExecutor listenerExecutor) { 29 | listenerExecutors.add(listenerExecutor); 30 | Collections.sort(listenerExecutors); 31 | refreshListenerCache(); 32 | } 33 | 34 | /** 35 | * 分派事件 36 | * (先执行优先级升序,再执行优先级降序) 37 | * 38 | * @param event 事件 39 | * @throws Throwable 执行过程中发生任何异常都会往外抛 40 | */ 41 | public void dispatch(Object event) throws Throwable { 42 | // 获取该事件类型的监听器缓存 43 | List theListenerExecutors = listenerExecutorsCache.get(resolver.resolve(event)); 44 | if (theListenerExecutors != null) { 45 | // 执行监听器 46 | for (ListenerExecutor listenerExecutor : theListenerExecutors) { 47 | listenerExecutor.execute(event); 48 | } 49 | } 50 | } 51 | 52 | // 刷新监听器缓存 53 | private void refreshListenerCache() { 54 | listenerExecutorsCache = new HashMap<>(); 55 | // 获取本总线所有的事件类型 56 | Set eventTypes = new HashSet<>(); 57 | for (ListenerExecutor listenerExecutor : listenerExecutors) { 58 | eventTypes.addAll(listenerExecutor.getEventTypes(true)); 59 | eventTypes.addAll(listenerExecutor.getEventTypes(false)); 60 | } 61 | // 根据事件类型设置缓存 62 | for (Object eventType : eventTypes) { 63 | // 特定事件类型的监听器缓存 64 | List theListenerExecutors = new ArrayList<>(); 65 | // 获取指定事件类型的升序监听器 66 | for (ListenerExecutor listenerExecutor : listenerExecutors) { 67 | if (listenerExecutor.getEventTypes(true).contains(eventType)) { 68 | theListenerExecutors.add(listenerExecutor); 69 | } 70 | } 71 | // 获取指定事件类型的降序监听器 72 | for (int i = listenerExecutors.size() - 1; i >= 0; i--) { 73 | ListenerExecutor listenerExecutor = listenerExecutors.get(i); 74 | if (listenerExecutor.getEventTypes(false).contains(eventType)) { 75 | theListenerExecutors.add(listenerExecutor); 76 | } 77 | } 78 | // 设置缓存 79 | listenerExecutorsCache.put(eventType, theListenerExecutors); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /halo-utils/src/main/java/org/xujin/halo/utils/reflect/BeanMapper.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.utils.reflect; 2 | 3 | import java.util.List; 4 | 5 | import ma.glasnost.orika.MapperFacade; 6 | import ma.glasnost.orika.MapperFactory; 7 | import ma.glasnost.orika.impl.DefaultMapperFactory; 8 | import ma.glasnost.orika.metadata.Type; 9 | import ma.glasnost.orika.metadata.TypeFactory; 10 | 11 | /** 12 | * @author xujin
13 | * 简单封装orika, 实现深度的BeanOfClasssA<->BeanOfClassB复制 不要是用Apache Common 14 | * BeanUtils进行类复制,每次就行反射查询对象的属性列表, 非常缓慢. 15 | */ 16 | public class BeanMapper { 17 | 18 | private static MapperFacade mapper; 19 | 20 | static { 21 | MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); 22 | mapper = mapperFactory.getMapperFacade(); 23 | } 24 | 25 | /** 26 | * 简单的复制出新类型对象. 27 | * 28 | * 通过source.getClass() 获得源Class 29 | */ 30 | public static D map(S source, Class destinationClass) { 31 | return mapper.map(source, destinationClass); 32 | } 33 | 34 | /** 35 | * 极致性能的复制出新类型对象. 36 | * 37 | * 预先通过BeanMapper.getType() 静态获取并缓存Type类型,在此处传入 38 | */ 39 | public static D map(S source, Type sourceType, Type destinationType) { 40 | return mapper.map(source, sourceType, destinationType); 41 | } 42 | 43 | /** 44 | * 简单的复制出新对象列表到ArrayList 45 | * 46 | * 不建议使用mapper.mapAsList(Iterable,Class)接口, sourceClass需要反射,实在有点慢 47 | */ 48 | public static List mapList(Iterable sourceList, Class sourceClass, 49 | Class destinationClass) { 50 | return mapper.mapAsList(sourceList, TypeFactory.valueOf(sourceClass), 51 | TypeFactory.valueOf(destinationClass)); 52 | } 53 | 54 | /** 55 | * 极致性能的复制出新类型对象到ArrayList. 56 | * 57 | * 预先通过BeanMapper.getType() 静态获取并缓存Type类型,在此处传入 58 | */ 59 | public static List mapList(Iterable sourceList, Type sourceType, 60 | Type destinationType) { 61 | return mapper.mapAsList(sourceList, sourceType, destinationType); 62 | } 63 | 64 | /** 65 | * 简单复制出新对象列表到数组 66 | * 67 | * 通过source.getComponentType() 获得源Class 68 | */ 69 | public static D[] mapArray(final D[] destination, final S[] source, 70 | final Class destinationClass) { 71 | return mapper.mapAsArray(destination, source, destinationClass); 72 | } 73 | 74 | /** 75 | * 极致性能的复制出新类型对象到数组 76 | * 77 | * 预先通过BeanMapper.getType() 静态获取并缓存Type类型,在此处传入 78 | */ 79 | public static D[] mapArray(D[] destination, S[] source, Type sourceType, 80 | Type destinationType) { 81 | return mapper.mapAsArray(destination, source, sourceType, destinationType); 82 | } 83 | 84 | /** 85 | * 预先获取orika转换所需要的Type,避免每次转换. 86 | */ 87 | public static Type getType(final Class rawType) { 88 | return TypeFactory.valueOf(rawType); 89 | } 90 | } -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/transaction/FlowTxParser.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.transaction; 2 | 3 | import org.xujin.halo.flow.annotation.transaction.FlowTx; 4 | import org.xujin.halo.flow.engine.TargetContext; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.aop.support.AopUtils; 8 | import org.springframework.core.ResolvableType; 9 | import org.springframework.transaction.PlatformTransactionManager; 10 | import org.springframework.util.ClassUtils; 11 | 12 | import java.lang.reflect.Method; 13 | import java.lang.reflect.Modifier; 14 | 15 | /** 16 | * 流程事务解析器 17 | */ 18 | public class FlowTxParser { 19 | // 日志记录器 20 | private static final Logger logger = LoggerFactory.getLogger(FlowTxParser.class); 21 | 22 | /** 23 | * 解析流程事务 24 | * 25 | * @param flowTx 流程事务 26 | * @param transactionManager 事务管理器 27 | * @return 流程事务执行器 28 | */ 29 | public static FlowTxExecutor parseFlowTx(Object flowTx, PlatformTransactionManager transactionManager) { 30 | // 获取目标class(应对AOP代理情况) 31 | Class flowTxClass = AopUtils.getTargetClass(flowTx); 32 | logger.debug("解析流程事务:{}", ClassUtils.getQualifiedName(flowTxClass)); 33 | FlowTx flowTxAnnotation = flowTxClass.getAnnotation(FlowTx.class); 34 | // 创建流程事务执行器 35 | FlowTxExecutor flowTxExecutor = new FlowTxExecutor(flowTxAnnotation.flow(), flowTx, transactionManager); 36 | for (Method method : flowTxClass.getDeclaredMethods()) { 37 | for (Class clazz : FlowTxExecutor.FLOW_TX_OPERATE_ANNOTATIONS) { 38 | if (method.isAnnotationPresent(clazz)) { 39 | // 设置流程事务操作执行器 40 | flowTxExecutor.setOperateExecutor(clazz, parseFlowTxOperate(method)); 41 | break; 42 | } 43 | } 44 | } 45 | flowTxExecutor.validate(); 46 | 47 | return flowTxExecutor; 48 | } 49 | 50 | // 解析流程事务操作 51 | private static FlowTxExecutor.FlowTxOperateExecutor parseFlowTxOperate(Method method) { 52 | logger.debug("解析流程事务方法:{}", method); 53 | // 校验方法类型 54 | if (!Modifier.isPublic(method.getModifiers())) { 55 | throw new IllegalArgumentException("流程事务方法" + ClassUtils.getQualifiedMethodName(method) + "必须是public类型"); 56 | } 57 | // 校验入参 58 | Class[] parameterTypes = method.getParameterTypes(); 59 | if (parameterTypes.length != 1) { 60 | throw new IllegalArgumentException("流程事务方法" + ClassUtils.getQualifiedMethodName(method) + "的入参必须是(TargetContext)"); 61 | } 62 | if (parameterTypes[0] != TargetContext.class) { 63 | throw new IllegalArgumentException("流程事务方法" + ClassUtils.getQualifiedMethodName(method) + "的入参必须是(TargetContext)"); 64 | } 65 | // 获取目标对象类型 66 | ResolvableType resolvableType = ResolvableType.forMethodParameter(method, 0); 67 | Class classOfTarget = resolvableType.getGeneric(0).resolve(Object.class); 68 | // 校验返回参数 69 | if (method.getReturnType() != classOfTarget) { 70 | throw new IllegalArgumentException("流程事务方法" + ClassUtils.getQualifiedMethodName(method) + "的返回类型必须是目标对象类型"); 71 | } 72 | 73 | return new FlowTxExecutor.FlowTxOperateExecutor(method, classOfTarget); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /halo-core/src/main/java/org/xujin/halo/boot/RegisterFactory.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xujin.halo.boot; 3 | 4 | import org.xujin.halo.command.Command; 5 | import org.xujin.halo.command.PostInterceptor; 6 | import org.xujin.halo.command.PreInterceptor; 7 | import org.xujin.halo.common.CoreConstant; 8 | import org.xujin.halo.event.EventHandler; 9 | import org.xujin.halo.exception.InfraException; 10 | import org.xujin.halo.extension.Extension; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | /** 15 | * RegisterFactory 16 | * 17 | * @author xujin 18 | */ 19 | @Component 20 | public class RegisterFactory{ 21 | 22 | @Autowired 23 | private PreInterceptorRegister preInterceptorRegister; 24 | @Autowired 25 | private PostInterceptorRegister postInterceptorRegister; 26 | @Autowired 27 | private CommandRegister commandRegister; 28 | @Autowired 29 | private ExtensionRegister extensionRegister; 30 | @Autowired 31 | private EventRegister eventRegister; 32 | @Autowired 33 | private PlainValidatorRegister plainValidatorRegister; 34 | @Autowired 35 | private PlainRuleRegister plainRuleRegister; 36 | 37 | public RegisterI getRegister(Class targetClz) { 38 | PreInterceptor preInterceptorAnn = targetClz.getDeclaredAnnotation(PreInterceptor.class); 39 | if (preInterceptorAnn != null) { 40 | return preInterceptorRegister; 41 | } 42 | PostInterceptor postInterceptorAnn = targetClz.getDeclaredAnnotation(PostInterceptor.class); 43 | if (postInterceptorAnn != null) { 44 | return postInterceptorRegister; 45 | } 46 | Command commandAnn = targetClz.getDeclaredAnnotation(Command.class); 47 | if (commandAnn != null) { 48 | return commandRegister; 49 | } 50 | Extension extensionAnn = targetClz.getDeclaredAnnotation(Extension.class); 51 | if (extensionAnn != null) { 52 | return extensionRegister; 53 | } 54 | if (isPlainValidator(targetClz)) { 55 | return plainValidatorRegister; 56 | } 57 | if (isPlainRule(targetClz)) { 58 | return plainRuleRegister; 59 | } 60 | EventHandler eventHandlerAnn = targetClz.getDeclaredAnnotation(EventHandler.class); 61 | if (eventHandlerAnn != null) { 62 | return eventRegister; 63 | } 64 | return null; 65 | } 66 | 67 | private boolean isPlainRule(Class targetClz) { 68 | if (ClassInterfaceChecker.check(targetClz, CoreConstant.RULEI_CLASS) && makeSureItsNotExtensionPoint(targetClz)) { 69 | return true; 70 | } 71 | return false; 72 | } 73 | 74 | private boolean isPlainValidator(Class targetClz) { 75 | if (ClassInterfaceChecker.check(targetClz, CoreConstant.VALIDATORI_CLASS) && makeSureItsNotExtensionPoint(targetClz)) { 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | private boolean makeSureItsNotExtensionPoint(Class targetClz) { 82 | if (ClassInterfaceChecker.check(targetClz, CoreConstant.EXTENSIONPOINT_CLASS)) { 83 | throw new InfraException( 84 | "Please add @Extension for " + targetClz.getSimpleName() + " since it's a ExtensionPoint"); 85 | } 86 | return true; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /halo-event/src/main/java/org/xujin/halo/event/listener/ListenerParser.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.event.listener; 2 | 3 | import org.xujin.halo.event.annotation.listener.Listen; 4 | import org.xujin.halo.event.annotation.listener.Listener; 5 | import org.xujin.halo.event.extension.EventTypeResolver; 6 | import org.xujin.halo.event.extension.ListenResolver; 7 | import org.xujin.halo.event.extension.ListenerType; 8 | import org.xujin.halo.event.listener.ListenerExecutor.ListenExecutor; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.aop.support.AopUtils; 12 | import org.springframework.cglib.core.ReflectUtils; 13 | import org.springframework.core.annotation.AnnotatedElementUtils; 14 | import org.springframework.util.ClassUtils; 15 | 16 | import java.lang.reflect.Method; 17 | import java.lang.reflect.Modifier; 18 | 19 | /** 20 | * 监听器解析器 21 | */ 22 | public class ListenerParser { 23 | // 日志记录器 24 | private static final Logger logger = LoggerFactory.getLogger(ListenerParser.class); 25 | 26 | /** 27 | * 解析监听器 28 | * 29 | * @param listener 监听器 30 | * @return 监听器执行器 31 | */ 32 | public static ListenerExecutor parseListener(Object listener) { 33 | // 获取目标class(应对AOP代理情况) 34 | Class listenerClass = AopUtils.getTargetClass(listener); 35 | logger.debug("解析监听器:{}", ClassUtils.getQualifiedName(listenerClass)); 36 | // 此处得到的@Listener是已经经过@AliasFor属性别名进行属性同步后的结果 37 | Listener listenerAnnotation = AnnotatedElementUtils.findMergedAnnotation(listenerClass, Listener.class); 38 | // 创建监听器执行器 39 | ListenerExecutor listenerExecutor = new ListenerExecutor(listenerAnnotation.type(), listenerAnnotation.priority(), listener, parseEventTypeResolver(listenerAnnotation.type())); 40 | for (Method method : listenerClass.getDeclaredMethods()) { 41 | Listen listenAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, Listen.class); 42 | if (listenAnnotation != null) { 43 | ListenExecutor listenExecutor = parseListen(listenAnnotation, method); 44 | listenerExecutor.addListenExecutor(listenExecutor); 45 | } 46 | } 47 | listenerExecutor.validate(); 48 | 49 | return listenerExecutor; 50 | } 51 | 52 | /** 53 | * 通过监听器类型解析得到事件类型解决器 54 | * 55 | * @param clazz 监听器类型 56 | */ 57 | public static EventTypeResolver parseEventTypeResolver(Class clazz) { 58 | ListenerType listenerType = (ListenerType) ReflectUtils.newInstance(clazz); 59 | return listenerType.getResolver(); 60 | } 61 | 62 | // 解析监听方法 63 | private static ListenExecutor parseListen(Listen listenAnnotation, Method method) { 64 | logger.debug("解析监听方法:{}", method); 65 | // 校验方法类型 66 | if (!Modifier.isPublic(method.getModifiers())) { 67 | throw new IllegalArgumentException("监听方法" + ClassUtils.getQualifiedMethodName(method) + "必须是public类型"); 68 | } 69 | // 校验返回类型 70 | if (method.getReturnType() != void.class) { 71 | throw new IllegalArgumentException("监听方法" + ClassUtils.getQualifiedMethodName(method) + "的返回必须是void"); 72 | } 73 | // 创建监听解决器 74 | ListenResolver resolver = (ListenResolver) ReflectUtils.newInstance(listenAnnotation.resolver()); 75 | resolver.init(method); 76 | 77 | return new ListenExecutor(resolver, listenAnnotation.priorityAsc(), method); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /halo-flow/src/main/java/org/xujin/halo/flow/processor/ProcessorParser.java: -------------------------------------------------------------------------------- 1 | package org.xujin.halo.flow.processor; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.xujin.halo.flow.annotation.processor.Processor; 5 | import org.xujin.halo.flow.annotation.processor.ProcessorExecute; 6 | import org.xujin.halo.flow.engine.TargetContext; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.aop.support.AopUtils; 10 | import org.springframework.core.ResolvableType; 11 | import org.springframework.util.ClassUtils; 12 | 13 | import java.lang.reflect.Method; 14 | import java.lang.reflect.Modifier; 15 | 16 | /** 17 | * 处理器解析器 18 | */ 19 | public class ProcessorParser { 20 | // 日志记录器 21 | private static final Logger logger = LoggerFactory.getLogger(ProcessorParser.class); 22 | 23 | /** 24 | * 解析处理器 25 | * 26 | * @param processor 处理器 27 | * @return 处理器执行器 28 | */ 29 | public static ProcessorExecutor parseProcessor(Object processor) { 30 | // 获取目标class(应对AOP代理情况) 31 | Class processorClass = AopUtils.getTargetClass(processor); 32 | logger.debug("解析处理器:{}", ClassUtils.getQualifiedName(processorClass)); 33 | // 获取处理器名称 34 | String processorName = processorClass.getAnnotation(Processor.class).name(); 35 | if (StringUtils.isEmpty(processorName)) { 36 | processorName = ClassUtils.getShortNameAsProperty(processorClass); 37 | } 38 | // 创建处理器执行器 39 | ProcessorExecutor processorExecutor = new ProcessorExecutor(processorName, processor); 40 | for (Method method : processorClass.getDeclaredMethods()) { 41 | for (Class clazz : ProcessorExecutor.PROCESSOR_METHOD_ANNOTATIONS) { 42 | if (method.isAnnotationPresent(clazz)) { 43 | // 设置处理器方法执行器 44 | processorExecutor.setMethodExecutor(clazz, parseProcessorMethod(clazz, method)); 45 | break; 46 | } 47 | } 48 | } 49 | processorExecutor.validate(); 50 | 51 | return processorExecutor; 52 | } 53 | 54 | /** 55 | * 解析处理器方法 56 | */ 57 | private static ProcessorExecutor.ProcessorMethodExecutor parseProcessorMethod(Class clazz, Method method) { 58 | logger.debug("解析处理器方法:{}", method); 59 | // 校验方法类型 60 | if (!Modifier.isPublic(method.getModifiers())) { 61 | throw new IllegalArgumentException("处理器方法" + ClassUtils.getQualifiedMethodName(method) + "必须是public类型"); 62 | } 63 | // 校验入参 64 | Class[] parameterTypes = method.getParameterTypes(); 65 | if (parameterTypes.length != 1) { 66 | throw new IllegalArgumentException("处理器方法" + ClassUtils.getQualifiedMethodName(method) + "入参必须是(TargetContext)"); 67 | } 68 | if (parameterTypes[0] != TargetContext.class) { 69 | throw new IllegalArgumentException("处理器方法" + ClassUtils.getQualifiedMethodName(method) + "入参必须是(TargetContext)"); 70 | } 71 | // 校验返回类型 72 | if (clazz != ProcessorExecute.class && method.getReturnType() != void.class) { 73 | throw new IllegalArgumentException("非@ProcessorExecute类型的处理器方法" + ClassUtils.getQualifiedMethodName(method) + "的返回类型必须是void"); 74 | } 75 | // 获取目标对象类型 76 | ResolvableType resolvableType = ResolvableType.forMethodParameter(method, 0); 77 | Class classOfTarget = resolvableType.getGeneric(0).resolve(Object.class); 78 | 79 | return new ProcessorExecutor.ProcessorMethodExecutor(method, classOfTarget); 80 | } 81 | } 82 | --------------------------------------------------------------------------------