eventHandlerIList = null;
+ Class cls = eventClass;
+ eventHandlerIList = eventRepository.get(cls);
+ return eventHandlerIList;
+ }
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/Assert.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/Assert.java
new file mode 100644
index 000000000..4ad31e93c
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/Assert.java
@@ -0,0 +1,92 @@
+package com.alibaba.cola.exception;
+
+import com.alibaba.cola.dto.ErrorCodeI;
+import com.alibaba.cola.exception.framework.BasicErrorCode;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Assertion utility class that assists in validating arguments.
+ *
+ * Useful for identifying programmer errors early and clearly at runtime.
+ *
+ *
For example, if the contract of a public method states it does not
+ * allow {@code null} arguments, {@code Assert} can be used to validate that
+ * contract.
+ *
+ * For example:
+ *
+ *
+ * Assert.notNull(clazz, "The class must not be null");
+ * Assert.isTrue(i > 0, "The value must be greater than zero");
+ *
+ * This class is empowered by {@link org.springframework.util.Assert}
+ *
+ * @author Frank Zhang
+ * @date 2019-01-13 11:49 AM
+ */
+public abstract class Assert {
+
+ /**
+ * Assert a boolean expression, throwing {@code BizException}
+ *
+ * for example
+ *
+ * Assert.isTrue(i != 0, errorCode.B_ORDER_illegalNumber, "The order number can not be zero");
+ *
+ * @param expression a boolean expression
+ * @param errorCode
+ * @param message the exception message to use if the assertion fails
+ * @throws BizException if expression is {@code false}
+ */
+ public static void isTrue(boolean expression, ErrorCodeI errorCode, String message){
+ if (!expression) {
+ throw new BizException(errorCode, message);
+ }
+ }
+
+ public static void isTrue(boolean expression, String message) {
+ isTrue(expression, BasicErrorCode.BIZ_ERROR, message);
+ }
+
+ public static void isTrue(boolean expression) {
+ isTrue(expression, "[Assertion failed] - this expression must be true");
+ }
+
+ public static void notNull(Object object, ErrorCodeI errorCode, String message) {
+ if (object == null) {
+ throw new BizException(errorCode, message);
+ }
+ }
+
+ public static void notNull(Object object, String message) {
+ notNull(object, BasicErrorCode.BIZ_ERROR, message);
+ }
+
+ public static void notNull(Object object){
+ notNull(object, BasicErrorCode.BIZ_ERROR, "[Assertion failed] - the argument "+object+" must not be null");
+ }
+
+ public static void notEmpty(Collection> collection) {
+ notEmpty(collection,
+ "[Assertion failed] - this collection must not be empty: it must contain at least 1 element");
+ }
+
+ public static void notEmpty(Collection> collection, String message) {
+ if (CollectionUtils.isEmpty(collection)) {
+ throw new BizException(message);
+ }
+ }
+
+ public static void notEmpty(Map, ?> map, String message) {
+ if (CollectionUtils.isEmpty(map)) {
+ throw new BizException(message);
+ }
+ }
+
+ public static void notEmpty(Map, ?> map) {
+ notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry");
+ }
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/BizException.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/BizException.java
new file mode 100644
index 000000000..f9e5b0099
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/BizException.java
@@ -0,0 +1,28 @@
+package com.alibaba.cola.exception;
+
+import com.alibaba.cola.dto.ErrorCodeI;
+import com.alibaba.cola.exception.framework.BaseException;
+import com.alibaba.cola.exception.framework.BasicErrorCode;
+
+/**
+ * BizException is known Exception, no need retry
+ */
+public class BizException extends BaseException {
+
+ private static final long serialVersionUID = 1L;
+
+ public BizException(String errMessage){
+ super(errMessage);
+ this.setErrCode(BasicErrorCode.BIZ_ERROR);
+ }
+
+ public BizException(ErrorCodeI errCode, String errMessage){
+ super(errMessage);
+ this.setErrCode(errCode);
+ }
+
+ public BizException(String errMessage, Throwable e) {
+ super(errMessage, e);
+ this.setErrCode(BasicErrorCode.BIZ_ERROR);
+ }
+}
\ No newline at end of file
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/ExceptionHandlerI.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/ExceptionHandlerI.java
new file mode 100644
index 000000000..3b68ed70b
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/ExceptionHandlerI.java
@@ -0,0 +1,14 @@
+package com.alibaba.cola.exception;
+
+import com.alibaba.cola.dto.Command;
+import com.alibaba.cola.dto.Response;
+
+/**
+ * ExceptionHandlerI provide a backdoor that Application can override the default Exception handling
+ *
+ * @author Frank Zhang
+ * @date 2019-01-02 11:25 PM
+ */
+public interface ExceptionHandlerI {
+ public void handleException(Command cmd, Response response, Exception exception);
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/SysException.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/SysException.java
new file mode 100644
index 000000000..e3b0953b1
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/SysException.java
@@ -0,0 +1,35 @@
+package com.alibaba.cola.exception;
+
+import com.alibaba.cola.dto.ErrorCodeI;
+import com.alibaba.cola.exception.framework.BaseException;
+import com.alibaba.cola.exception.framework.BasicErrorCode;
+
+/**
+ * System Exception is unexpected Exception, retry might work again
+ *
+ * @author Danny.Lee 2018/1/27
+ */
+public class SysException extends BaseException {
+
+ private static final long serialVersionUID = 4355163994767354840L;
+
+ public SysException(String errMessage){
+ super(errMessage);
+ this.setErrCode(BasicErrorCode.SYS_ERROR);
+ }
+
+ public SysException(ErrorCodeI errCode, String errMessage) {
+ super(errMessage);
+ this.setErrCode(errCode);
+ }
+
+ public SysException(String errMessage, Throwable e) {
+ super(errMessage, e);
+ this.setErrCode(BasicErrorCode.SYS_ERROR);
+ }
+
+ public SysException(String errMessage, ErrorCodeI errorCode, Throwable e) {
+ super(errMessage, e);
+ this.setErrCode(errorCode);
+ }
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/BaseException.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/BaseException.java
new file mode 100644
index 000000000..94cae8f33
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/BaseException.java
@@ -0,0 +1,33 @@
+package com.alibaba.cola.exception.framework;
+
+import com.alibaba.cola.dto.ErrorCodeI;
+
+/**
+ *
+ * Base Exception is the parent of all exceptions
+ *
+ * @author fulan.zjf 2017年10月22日 上午12:00:39
+ */
+public abstract class BaseException extends RuntimeException{
+
+ private static final long serialVersionUID = 1L;
+
+ private ErrorCodeI errCode;
+
+ public BaseException(String errMessage){
+ super(errMessage);
+ }
+
+ public BaseException(String errMessage, Throwable e) {
+ super(errMessage, e);
+ }
+
+ public ErrorCodeI getErrCode() {
+ return errCode;
+ }
+
+ public void setErrCode(ErrorCodeI errCode) {
+ this.errCode = errCode;
+ }
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/BasicErrorCode.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/BasicErrorCode.java
new file mode 100644
index 000000000..f29fc05b9
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/BasicErrorCode.java
@@ -0,0 +1,39 @@
+package com.alibaba.cola.exception.framework;
+
+import com.alibaba.cola.dto.ErrorCodeI;
+
+/**
+ *
+ * There are only 3 basic ErrorCode:
+ * COLA_ERROR
+ * BIZ_ERROR
+ * SYS_ERROR
+ *
+ * Created by fulan.zjf on 2017/12/18.
+ */
+public enum BasicErrorCode implements ErrorCodeI {
+
+ BIZ_ERROR("BIZ_ERROR" , "通用的业务逻辑错误"),
+
+ COLA_ERROR("COLA_FRAMEWORK_ERROR" , "COLA框架错误"),
+
+ SYS_ERROR("SYS_ERROR" , "未知的系统错误" );
+
+ private String errCode;
+ private String errDesc;
+
+ private BasicErrorCode(String errCode, String errDesc){
+ this.errCode = errCode;
+ this.errDesc = errDesc;
+ }
+
+ @Override
+ public String getErrCode() {
+ return errCode;
+ }
+
+ @Override
+ public String getErrDesc() {
+ return errDesc;
+ }
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/ColaException.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/ColaException.java
new file mode 100644
index 000000000..bab5be9ff
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/ColaException.java
@@ -0,0 +1,22 @@
+package com.alibaba.cola.exception.framework;
+
+/**
+ *
+ * Infrastructure Exception
+ *
+ * @author fulan.zjf 2017年10月22日 下午5:56:57
+ */
+public class ColaException extends BaseException {
+
+ private static final long serialVersionUID = 1L;
+
+ public ColaException(String errMessage){
+ super(errMessage);
+ this.setErrCode(BasicErrorCode.COLA_ERROR);
+ }
+
+ public ColaException(String errMessage, Throwable e) {
+ super(errMessage, e);
+ this.setErrCode(BasicErrorCode.COLA_ERROR);
+ }
+}
\ No newline at end of file
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/DefaultExceptionHandler.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/DefaultExceptionHandler.java
new file mode 100644
index 000000000..66856bfb9
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/DefaultExceptionHandler.java
@@ -0,0 +1,56 @@
+package com.alibaba.cola.exception.framework;
+
+import com.alibaba.cola.dto.Command;
+import com.alibaba.cola.dto.ErrorCodeI;
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.exception.ExceptionHandlerI;
+import com.alibaba.cola.logger.Logger;
+import com.alibaba.cola.logger.LoggerFactory;
+
+/**
+ * DefaultExceptionHandler
+ *
+ * @author Frank Zhang
+ * @date 2019-01-08 9:51 AM
+ */
+public class DefaultExceptionHandler implements ExceptionHandlerI {
+
+ private Logger logger = LoggerFactory.getLogger(DefaultExceptionHandler.class);
+
+ public static DefaultExceptionHandler singleton = new DefaultExceptionHandler();
+
+ @Override
+ public void handleException(Command cmd, Response response, Exception exception) {
+ buildResponse(response, exception);
+ printLog(cmd, response, exception);
+ }
+
+ private void printLog(Command cmd, Response response, Exception exception) {
+ if(exception instanceof BaseException){
+ //biz exception is expected, only warn it
+ logger.warn(buildErrorMsg(cmd, response));
+ }
+ else{
+ //sys exception should be monitored, and pay attention to it
+ logger.error(buildErrorMsg(cmd, response), exception);
+ }
+ }
+
+ private String buildErrorMsg(Command cmd, Response response) {
+ return "Process [" + cmd + "] failed, errorCode: "
+ + response.getErrCode() + " errorMsg:"
+ + response.getErrMessage();
+ }
+
+ private void buildResponse(Response response, Exception exception) {
+ if (exception instanceof BaseException) {
+ ErrorCodeI errCode = ((BaseException) exception).getErrCode();
+ response.setErrCode(errCode.getErrCode());
+ }
+ else {
+ response.setErrCode(BasicErrorCode.SYS_ERROR.getErrCode());
+ }
+ response.setErrMessage(exception.getMessage());
+ response.setSuccess(false);
+ }
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/ExceptionHandlerFactory.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/ExceptionHandlerFactory.java
new file mode 100644
index 000000000..81d1d749f
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/framework/ExceptionHandlerFactory.java
@@ -0,0 +1,24 @@
+package com.alibaba.cola.exception.framework;
+
+import com.alibaba.cola.common.ApplicationContextHelper;
+import com.alibaba.cola.exception.ExceptionHandlerI;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+
+/**
+ * ExceptionHandlerFactory
+ *
+ * @author Frank Zhang
+ * @date 2019-01-08 9:51 AM
+ */
+public class ExceptionHandlerFactory {
+
+ public static ExceptionHandlerI getExceptionHandler(){
+ try {
+ return ApplicationContextHelper.getBean(ExceptionHandlerI.class);
+ }
+ catch (NoSuchBeanDefinitionException ex){
+ return DefaultExceptionHandler.singleton;
+ }
+ }
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/exception/package-info.java b/cola-framework-core/src/main/java/com/alibaba/cola/exception/package-info.java
new file mode 100644
index 000000000..1f8451e8b
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/exception/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package defines all kinds of Exceptions of Application.
+ *
+ * @author fulan.zjf
+ */
+package com.alibaba.cola.exception;
\ No newline at end of file
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/extension/Extension.java b/cola-framework-core/src/main/java/com/alibaba/cola/extension/Extension.java
new file mode 100644
index 000000000..180dd1b8e
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/extension/Extension.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 Alibaba.com All right reserved. This software is the
+ * confidential and proprietary information of Alibaba.com ("Confidential
+ * Information"). You shall not disclose such Confidential Information and shall
+ * use it only in accordance with the terms of the license agreement you entered
+ * into with Alibaba.com.
+ */
+package com.alibaba.cola.extension;
+
+import com.alibaba.cola.common.ColaConstant;
+import org.springframework.stereotype.Component;
+
+import java.lang.annotation.*;
+
+/**
+ * Extension
+ * @author fulan.zjf 2017-11-05
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@Component
+public @interface Extension {
+ String bizId() default BizScenario.DEFAULT_BIZ_ID;
+ String useCase() default BizScenario.DEFAULT_USE_CASE;
+ String scenario() default BizScenario.DEFAULT_SCENARIO;
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionCoordinate.java b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionCoordinate.java
new file mode 100644
index 000000000..be2edde1a
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionCoordinate.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017 Alibaba.com All right reserved. This software is the
+ * confidential and proprietary information of Alibaba.com ("Confidential
+ * Information"). You shall not disclose such Confidential Information and shall
+ * use it only in accordance with the terms of the license agreement you entered
+ * into with Alibaba.com.
+ */
+package com.alibaba.cola.extension;
+
+/**
+ * Extension Coordinate(扩展坐标) is used to uniquely position an Extension
+ * @author fulan.zjf 2017-11-05
+ */
+public class ExtensionCoordinate {
+
+ private String extensionPointName;
+ private String bizScenarioUniqueIdentity;
+
+
+
+ //Wrapper
+ private Class extensionPointClass;
+ private BizScenario bizScenario;
+
+ public Class getExtensionPointClass() {
+ return extensionPointClass;
+ }
+
+ public BizScenario getBizScenario() {
+ return bizScenario;
+ }
+
+ public static ExtensionCoordinate valueOf(Class extPtClass, BizScenario bizScenario){
+ return new ExtensionCoordinate(extPtClass, bizScenario);
+ }
+
+ public ExtensionCoordinate(Class extPtClass, BizScenario bizScenario){
+ this.extensionPointClass = extPtClass;
+ this.extensionPointName = extPtClass.getName();
+ this.bizScenario = bizScenario;
+ this.bizScenarioUniqueIdentity = bizScenario.getUniqueIdentity();
+ }
+
+ /**
+ * @param extensionPoint
+ * @param bizScenario
+ */
+ public ExtensionCoordinate(String extensionPoint, String bizScenario){
+ this.extensionPointName = extensionPoint;
+ this.bizScenarioUniqueIdentity = bizScenario;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((bizScenarioUniqueIdentity == null) ? 0 : bizScenarioUniqueIdentity.hashCode());
+ result = prime * result + ((extensionPointName == null) ? 0 : extensionPointName.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ ExtensionCoordinate other = (ExtensionCoordinate) obj;
+ if (bizScenarioUniqueIdentity == null) {
+ if (other.bizScenarioUniqueIdentity != null) return false;
+ } else if (!bizScenarioUniqueIdentity.equals(other.bizScenarioUniqueIdentity)) return false;
+ if (extensionPointName == null) {
+ if (other.extensionPointName != null) return false;
+ } else if (!extensionPointName.equals(other.extensionPointName)) return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ExtensionCoordinate [extensionPointName=" + extensionPointName + ", bizScenarioUniqueIdentity=" + bizScenarioUniqueIdentity + "]";
+ }
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionExecutor.java b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionExecutor.java
new file mode 100644
index 000000000..9953aa5ab
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionExecutor.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 Alibaba.com All right reserved. This software is the
+ * confidential and proprietary information of Alibaba.com ("Confidential
+ * Information"). You shall not disclose such Confidential Information and shall
+ * use it only in accordance with the terms of the license agreement you entered
+ * into with Alibaba.com.
+ */
+package com.alibaba.cola.extension;
+
+import com.alibaba.cola.boot.AbstractComponentExecutor;
+import com.alibaba.cola.common.ColaConstant;
+import com.alibaba.cola.exception.framework.ColaException;
+import com.alibaba.cola.logger.Logger;
+import com.alibaba.cola.logger.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * ExtensionExecutor
+ * @author fulan.zjf 2017-11-05
+ */
+@Component
+public class ExtensionExecutor extends AbstractComponentExecutor {
+
+ private Logger logger = LoggerFactory.getLogger(ExtensionExecutor.class);
+
+ @Autowired
+ private ExtensionRepository extensionRepository;
+
+ @Override
+ protected C locateComponent(Class targetClz, BizScenario bizScenario) {
+ C extension = locateExtension(targetClz, bizScenario);
+ logger.debug("[Located Extension]: "+extension.getClass().getSimpleName());
+ return extension;
+ }
+
+ /**
+ * if the bizScenarioUniqueIdentity is "ali.tmall.supermarket"
+ *
+ * the search path is as below:
+ * 1、first try to get extension by "ali.tmall.supermarket", if get, return it.
+ * 2、loop try to get extension by "ali.tmall", if get, return it.
+ * 3、loop try to get extension by "ali", if get, return it.
+ * 4、if not found, try the default extension
+ * @param targetClz
+ */
+ protected Ext locateExtension(Class targetClz, BizScenario bizScenario) {
+ checkNull(bizScenario);
+
+ Ext extension;
+ String bizScenarioUniqueIdentity = bizScenario.getUniqueIdentity();
+ logger.debug("BizScenario in locateExtension is : " + bizScenarioUniqueIdentity);
+
+ // first try
+ extension = firstTry(targetClz, bizScenarioUniqueIdentity);
+ if (extension != null) {
+ return extension;
+ }
+
+ // loop try
+ extension = loopTry(targetClz, bizScenarioUniqueIdentity);
+ if (extension != null) {
+ return extension;
+ }
+
+ throw new ColaException("Can not find extension with ExtensionPoint: "+targetClz+" BizScenario:"+bizScenarioUniqueIdentity);
+ }
+
+ private Ext firstTry(Class targetClz, String bizScenario) {
+ return (Ext)extensionRepository.getExtensionRepo().get(new ExtensionCoordinate(targetClz.getName(), bizScenario));
+ }
+
+ private Ext loopTry(Class targetClz, String bizScenario){
+ Ext extension;
+ if (bizScenario == null){
+ return null;
+ }
+ int lastDotIndex = bizScenario.lastIndexOf(ColaConstant.DOT_SEPARATOR);
+ while(lastDotIndex != -1){
+ bizScenario = bizScenario.substring(0, lastDotIndex);
+ extension =(Ext)extensionRepository.getExtensionRepo().get(new ExtensionCoordinate(targetClz.getName(), bizScenario));
+ if (extension != null) {
+ return extension;
+ }
+ lastDotIndex = bizScenario.lastIndexOf(ColaConstant.DOT_SEPARATOR);
+ }
+ return null;
+ }
+
+
+ private void checkNull(BizScenario bizScenario){
+ if(bizScenario == null){
+ throw new ColaException("BizScenario can not be null for extension");
+ }
+ }
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionPointI.java b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionPointI.java
new file mode 100644
index 000000000..1bd51a70d
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionPointI.java
@@ -0,0 +1,10 @@
+package com.alibaba.cola.extension;
+
+/**
+ * ExtensionPointI is the parent interface of all ExtensionPoints
+ * 扩展点表示一块逻辑在不同的业务有不同的实现,使用扩展点做接口申明,然后用Extension(扩展)去实现扩展点。
+ * @author fulan.zjf 2017-10-22
+ */
+public interface ExtensionPointI {
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionRepository.java b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionRepository.java
new file mode 100644
index 000000000..f53298dd7
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/extension/ExtensionRepository.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 Alibaba.com All right reserved. This software is the
+ * confidential and proprietary information of Alibaba.com ("Confidential
+ * Information"). You shall not disclose such Confidential Information and shall
+ * use it only in accordance with the terms of the license agreement you entered
+ * into with Alibaba.com.
+ */
+package com.alibaba.cola.extension;
+
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ExtensionRepository
+ * @author fulan.zjf 2017-11-05
+ */
+@Component
+public class ExtensionRepository {
+
+ public Map getExtensionRepo() {
+ return extensionRepo;
+ }
+
+ private Map extensionRepo = new HashMap<>();
+
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/extension/package-info.java b/cola-framework-core/src/main/java/com/alibaba/cola/extension/package-info.java
new file mode 100644
index 000000000..0a93d236d
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/extension/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Use {@link ExtensionPointI} to declare extension point, and use {@link Extension} Annotation to mark specific Extension.
+ *
+ * @author fulan.zjf
+ */
+package com.alibaba.cola.extension;
\ No newline at end of file
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/logger/Logger.java b/cola-framework-core/src/main/java/com/alibaba/cola/logger/Logger.java
new file mode 100644
index 000000000..65f4b515d
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/logger/Logger.java
@@ -0,0 +1,84 @@
+package com.alibaba.cola.logger;
+
+/**
+ * This is a typical DIP, by depending on ourselves logger, we can change the underline logger vendor easily
+ *
+ * @author fulan.zjf 2017年10月23日 下午11:58:54
+ */
+public interface Logger {
+
+ /**
+ * Log a message at the DEBUG level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void debug(String msg);
+
+ /**
+ * Log a message at the DEBUG level. support format.
+ *
+ * @param msg
+ * @param args
+ */
+ default public void debug(String msg, Object... args){
+ debug(String.format(msg, args));
+ }
+
+ /**
+ * Log a message at the INFO level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void info(String msg);
+
+ /**
+ * Log a message at the INFO level. support format.
+ *
+ * @param msg
+ * @param args
+ */
+ default public void info(String msg, Object... args){
+ info(String.format(msg, args));
+ }
+
+ /**
+ * Log a message at the WARN level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void warn(String msg);
+
+ /**
+ * Log a message at the WARN level. support format.
+ *
+ * @param msg
+ * @param args
+ */
+ default public void warn(String msg, Object... args){
+ warn(String.format(msg, args));
+ }
+ /**
+ * Log a message at the ERROR level.
+ *
+ * @param msg the message string to be logged
+ */
+ public void error(String msg);
+
+ /**
+ * Log a message at the ERROR level. support format.
+ * @param msg
+ * @param args
+ */
+ default public void error(String msg, Object... args){
+ error(String.format(msg, args));
+ }
+
+ /**
+ * Log an exception (throwable) at the ERROR level with an
+ * accompanying message.
+ *
+ * @param msg the message accompanying the exception
+ * @param t the exception (throwable) to log
+ */
+ public void error(String msg, Throwable t);
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/logger/LoggerFactory.java b/cola-framework-core/src/main/java/com/alibaba/cola/logger/LoggerFactory.java
new file mode 100644
index 000000000..a0f38d0ac
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/logger/LoggerFactory.java
@@ -0,0 +1,32 @@
+package com.alibaba.cola.logger;
+
+public class LoggerFactory {
+
+ private static boolean useSysLogger = false;
+
+ public static Logger getLogger(Class> clazz) {
+ if(useSysLogger)
+ return SysLogger.getLogger(clazz);
+ org.slf4j.Logger slfjLogger = org.slf4j.LoggerFactory.getLogger(clazz);
+ return new SLFJLogger(slfjLogger);
+ }
+
+ public static Logger getLogger(String loggerName) {
+ if(useSysLogger) {
+ return SysLogger.getLogger(loggerName);
+ }
+ org.slf4j.Logger slfjLogger = org.slf4j.LoggerFactory.getLogger(loggerName);
+ return new SLFJLogger(slfjLogger);
+ }
+
+ /**
+ * This is just for testing purpose, don't use it on product!
+ */
+ public static void activateSysLogger() {
+ useSysLogger = true;
+ }
+
+ public static void deactivateSysLogger() {
+ useSysLogger = false;
+ }
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/logger/SLFJLogger.java b/cola-framework-core/src/main/java/com/alibaba/cola/logger/SLFJLogger.java
new file mode 100644
index 000000000..6748f1718
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/logger/SLFJLogger.java
@@ -0,0 +1,39 @@
+package com.alibaba.cola.logger;
+
+public class SLFJLogger implements com.alibaba.cola.logger.Logger{
+
+ private org.slf4j.Logger slfjLogger;
+
+ public SLFJLogger(org.slf4j.Logger slfjLogger) {
+ this.slfjLogger = slfjLogger;
+ }
+
+ @Override
+ public void debug(String msg) {
+ slfjLogger.debug(msg);
+ }
+
+ @Override
+ public void info(String msg) {
+ slfjLogger.info(msg);
+
+ }
+
+ @Override
+ public void warn(String msg) {
+ slfjLogger.warn(msg);
+
+ }
+
+ @Override
+ public void error(String msg) {
+ slfjLogger.error(msg);
+
+ }
+
+ @Override
+ public void error(String msg, Throwable t) {
+ slfjLogger.error(msg, t);
+ }
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/logger/SysLogger.java b/cola-framework-core/src/main/java/com/alibaba/cola/logger/SysLogger.java
new file mode 100644
index 000000000..bdf70f906
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/logger/SysLogger.java
@@ -0,0 +1,46 @@
+package com.alibaba.cola.logger;
+
+public class SysLogger implements Logger{
+
+ private String loggerName;
+
+ private SysLogger(String loggerName){
+ this.loggerName = loggerName;
+ }
+
+ public static Logger getLogger(Class clz){
+ return new SysLogger(clz.getName());
+ }
+
+
+ public static Logger getLogger(String loggerName){
+ return new SysLogger(loggerName);
+ }
+
+ @Override
+ public void debug(String msg) {
+ System.out.println("["+loggerName+"] DEBUG: "+msg);
+ }
+
+ @Override
+ public void info(String msg) {
+ System.out.println("["+loggerName+"] INFO: "+msg);
+ }
+
+ @Override
+ public void warn(String msg) {
+ System.out.println("["+loggerName+"] WARN: "+msg);
+ }
+
+ @Override
+ public void error(String msg) {
+ System.err.println("["+loggerName+"] ERROR: "+msg);
+ }
+
+ @Override
+ public void error(String msg, Throwable t) {
+ System.err.println("["+loggerName+"] ERROR: "+msg);
+ t.printStackTrace();
+ }
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/logger/package-info.java b/cola-framework-core/src/main/java/com/alibaba/cola/logger/package-info.java
new file mode 100644
index 000000000..461ceb8f3
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/logger/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * CRM Logger is used to decouple and uniform logger usage with different vendors, typical DIP.
+ *
+ * @author fulan.zjf
+ */
+package com.alibaba.cola.logger;
\ No newline at end of file
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/Filter.java b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/Filter.java
new file mode 100644
index 000000000..8d1338ee9
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/Filter.java
@@ -0,0 +1,10 @@
+package com.alibaba.cola.pattern.filter;
+
+/**
+ *
+ */
+public interface Filter {
+
+ void doFilter(T context, FilterInvoker nextFilter);
+
+}
\ No newline at end of file
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterChain.java b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterChain.java
new file mode 100644
index 000000000..01f0b3f55
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterChain.java
@@ -0,0 +1,19 @@
+package com.alibaba.cola.pattern.filter;
+
+/**
+ * 拦截器链
+ * @author shawnzhan.zxy
+ * @date 2018/04/17
+ */
+public class FilterChain{
+
+ private FilterInvoker header;
+
+ public void doFilter(T context){
+ header.invoke(context);
+ }
+
+ public void setHeader(FilterInvoker header) {
+ this.header = header;
+ }
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterChainFactory.java b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterChainFactory.java
new file mode 100644
index 000000000..86e688253
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterChainFactory.java
@@ -0,0 +1,30 @@
+package com.alibaba.cola.pattern.filter;
+
+import com.alibaba.cola.common.ApplicationContextHelper;
+
+/**
+ * 责任链模式工厂
+ * @author shawnzhan.zxy
+ * @date 2018/04/17
+ */
+public class FilterChainFactory {
+
+ public static FilterChain buildFilterChain(Class... filterClsList) {
+ FilterInvoker last = new FilterInvoker(){};
+ FilterChain filterChain = new FilterChain();
+ for(int i = filterClsList.length - 1; i >= 0; i--){
+ FilterInvoker next = last;
+ Filter filter = (Filter)ApplicationContextHelper.getBean(filterClsList[i]);
+ last = new FilterInvoker(){
+ @Override
+ public void invoke(T context) {
+ filter.doFilter(context, next);
+ }
+ };
+ }
+ filterChain.setHeader(last);
+ return filterChain;
+ }
+
+
+}
diff --git a/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterInvoker.java b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterInvoker.java
new file mode 100644
index 000000000..4eecd4039
--- /dev/null
+++ b/cola-framework-core/src/main/java/com/alibaba/cola/pattern/filter/FilterInvoker.java
@@ -0,0 +1,10 @@
+package com.alibaba.cola.pattern.filter;
+
+/**
+ * @author shawnzhan.zxy
+ * @date 2018/04/17
+ */
+public interface FilterInvoker {
+
+ default public void invoke(T context){};
+}
diff --git a/cola-framework-core/src/main/resources/sample.properties b/cola-framework-core/src/main/resources/sample.properties
new file mode 100644
index 000000000..e69de29bb
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/SysLoggerPostProcessor.java b/cola-framework-core/src/test/java/com/alibaba/cola/SysLoggerPostProcessor.java
new file mode 100644
index 000000000..11bb9d87f
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/SysLoggerPostProcessor.java
@@ -0,0 +1,21 @@
+package com.alibaba.cola;
+
+import com.alibaba.cola.logger.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * SysLoggerPostProcessor
+ *
+ * @author Frank Zhang
+ * @date 2018-08-19 2:42 PM
+ */
+@Component
+public class SysLoggerPostProcessor implements BeanFactoryPostProcessor {
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ LoggerFactory.activateSysLogger();
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/TestSpringConfig.java b/cola-framework-core/src/test/java/com/alibaba/cola/TestSpringConfig.java
new file mode 100644
index 000000000..55a680eaa
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/TestSpringConfig.java
@@ -0,0 +1,26 @@
+package com.alibaba.cola;
+
+import com.alibaba.cola.boot.SpringBootstrap;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+/**
+ * TestSpringConfig
+ *
+ * @author Frank Zhang
+ * @date 2020-06-18 8:03 PM
+ */
+@Configuration
+@ComponentScan(value = {"com.alibaba.cola","com.alibaba.cola.test"})
+@PropertySource(value = {"/sample.properties"})
+public class TestSpringConfig {
+
+ @Bean(initMethod = "init")
+ public SpringBootstrap bootstrap() {
+ SpringBootstrap bootstrap = new SpringBootstrap();
+ return bootstrap;
+ }
+
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/CustomerCommandTest.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/CustomerCommandTest.java
new file mode 100644
index 000000000..2add17142
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/CustomerCommandTest.java
@@ -0,0 +1,126 @@
+package com.alibaba.cola.test;
+
+import com.alibaba.cola.TestSpringConfig;
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.exception.BizException;
+import com.alibaba.cola.extension.BizScenario;
+import com.alibaba.cola.test.customer.*;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * CustomerCommandTest
+ *
+ * @author Frank Zhang 2018-01-06 7:55 PM
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = {TestSpringConfig.class})
+public class CustomerCommandTest {
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Autowired
+ private CustomerServiceI customerService;
+
+ @Value("${bizScenarioUniqueIdentity}")
+ private String bizCode;
+
+ @Before
+ public void setUp() {
+ }
+
+ @Test
+ public void testBizOneAddCustomerSuccess(){
+ //1. Prepare
+ AddCustomerCmd addCustomerCmd = new AddCustomerCmd();
+ CustomerCO customerCO = new CustomerCO();
+ customerCO.setCompanyName("alibaba");
+ customerCO.setSource(Constants.SOURCE_RFQ);
+ customerCO.setCustomerType(CustomerType.IMPORTANT);
+ addCustomerCmd.setCustomerCO(customerCO);
+ BizScenario scenario = BizScenario.valueOf(Constants.BIZ_1);
+ addCustomerCmd.setBizScenario(scenario);
+
+ //2. Execute
+ Response response = customerService.addCustomer(addCustomerCmd);
+
+ //3. Expect Success
+ Assert.assertTrue(response.isSuccess());
+ }
+
+ @Test(expected = BizException.class)
+ public void testBizOneAddCustomerFailure(){
+ //1. Prepare
+ AddCustomerCmd addCustomerCmd = new AddCustomerCmd();
+ CustomerCO customerCO = new CustomerCO();
+ customerCO.setCompanyName("alibaba");
+ customerCO.setSource(Constants.SOURCE_AD);
+ addCustomerCmd.setCustomerCO(customerCO);
+ BizScenario scenario = BizScenario.valueOf(Constants.BIZ_2);
+ addCustomerCmd.setBizScenario(scenario);
+
+ //2. Execute
+ Response response = customerService.addCustomer(addCustomerCmd);
+
+ //3. Expect exception
+
+ }
+
+ @Test
+ public void testBizTwoAddCustomer(){
+ //1. Prepare
+ AddCustomerCmd addCustomerCmd = new AddCustomerCmd();
+ CustomerCO customerCO = new CustomerCO();
+ customerCO.setCompanyName("alibaba");
+ customerCO.setSource(Constants.SOURCE_AD);
+ customerCO.setCustomerType(CustomerType.IMPORTANT);
+ addCustomerCmd.setCustomerCO(customerCO);
+ BizScenario scenario = BizScenario.valueOf(Constants.BIZ_2);
+ addCustomerCmd.setBizScenario(scenario);
+ //2. Execute
+ Response response = customerService.addCustomer(addCustomerCmd);
+
+ //3. Expect Success
+ Assert.assertTrue(response.isSuccess());
+ }
+
+ /* @Test
+ public void testCompanyTypeViolation(){
+ AddCustomerCmd addCustomerCmd = new AddCustomerCmd();
+ CustomerCO customerCO = new CustomerCO();
+ customerCO.setCompanyName("alibaba");
+ customerCO.setSource(SourceType.AD.name());
+ customerCO.setCustomerType(CustomerType.VIP);
+ addCustomerCmd.setCustomerCO(customerCO);
+ BizScenario scenario = BizScenario.valueOf(Constants.BIZ_1);
+ addCustomerCmd.setBizScenario(scenario);
+ Response response = customerService.addCustomer(addCustomerCmd);
+
+ //Expect biz exception
+ Assert.assertFalse(response.isSuccess());
+ Assert.assertEquals(response.getErrCode(), BasicErrorCode.BIZ_ERROR.getErrCode());
+ }
+ */
+
+
+/* @Test
+ public void testParamValidationFail(){
+ AddCustomerCmd addCustomerCmd = new AddCustomerCmd();
+ BizScenario scenario = BizScenario.valueOf(Constants.BIZ_1);
+ addCustomerCmd.setBizScenario(scenario);
+ Response response = customerService.addCustomer(addCustomerCmd);
+
+ //Expect parameter validation error
+ Assert.assertFalse(response.isSuccess());
+ Assert.assertEquals(response.getErrCode(), BasicErrorCode.BIZ_ERROR.getErrCode());
+ }*/
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/EntityPrototypeTest.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/EntityPrototypeTest.java
new file mode 100644
index 000000000..88a5670fd
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/EntityPrototypeTest.java
@@ -0,0 +1,32 @@
+package com.alibaba.cola.test;
+
+import com.alibaba.cola.TestSpringConfig;
+import com.alibaba.cola.common.ApplicationContextHelper;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * EntityPrototypeTest
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 12:34 PM
+ */
+
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = {TestSpringConfig.class})
+public class EntityPrototypeTest {
+
+ @Test
+ public void testPrototype(){
+ CustomerEntity customerEntity1 = (CustomerEntity)ApplicationContextHelper.getBean(CustomerEntity.class);
+ System.out.println(customerEntity1);
+ CustomerEntity customerEntity2 = (CustomerEntity)ApplicationContextHelper.getBean(CustomerEntity.class);
+ System.out.println(customerEntity2);
+
+ Assert.assertFalse(customerEntity1 == customerEntity2); //It should be different objects
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/SpringConfigTest.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/SpringConfigTest.java
new file mode 100644
index 000000000..347befe8c
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/SpringConfigTest.java
@@ -0,0 +1,21 @@
+package com.alibaba.cola.test;
+
+import com.alibaba.cola.TestSpringConfig;
+import com.alibaba.cola.boot.SpringBootstrap;
+import com.alibaba.cola.logger.LoggerFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+/**
+ * SpringConfigTest
+ *
+ * @author Frank Zhang
+ * @date 2020-06-18 8:09 PM
+ */
+public class SpringConfigTest {
+ public static void main(String[] args) {
+ LoggerFactory.activateSysLogger();
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestSpringConfig.class);
+ SpringBootstrap bootstrap = (SpringBootstrap)context.getBean("bootstrap");
+ System.out.println(bootstrap);
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/AddCustomerCmd.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/AddCustomerCmd.java
new file mode 100644
index 000000000..3461c5015
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/AddCustomerCmd.java
@@ -0,0 +1,25 @@
+package com.alibaba.cola.test.customer;
+
+
+import com.alibaba.cola.dto.Command;
+
+/**
+ * AddCustomerCmd
+ *
+ * @author Frank Zhang 2018-01-06 7:28 PM
+ */
+public class AddCustomerCmd extends Command {
+
+
+ public CustomerCO getCustomerCO() {
+ return customerCO;
+ }
+
+ public void setCustomerCO(CustomerCO customerCO) {
+ this.customerCO = customerCO;
+ }
+
+ private CustomerCO customerCO;
+
+
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/AddCustomerCmdExe.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/AddCustomerCmdExe.java
new file mode 100644
index 000000000..fac1875ca
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/AddCustomerCmdExe.java
@@ -0,0 +1,48 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.extension.ExtensionExecutor;
+import com.alibaba.cola.logger.Logger;
+import com.alibaba.cola.logger.LoggerFactory;
+import com.alibaba.cola.test.customer.convertor.CustomerConvertorExtPt;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+import com.alibaba.cola.test.customer.validator.extensionpoint.AddCustomerValidatorExtPt;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * AddCustomerCmdExe
+ *
+ * @author Frank Zhang 2018-01-06 7:48 PM
+ */
+@Component
+public class AddCustomerCmdExe {
+
+ private Logger logger = LoggerFactory.getLogger(AddCustomerCmd.class);
+
+ @Resource
+ private ExtensionExecutor extensionExecutor;
+
+ @Resource
+ private DomainEventPublisher domainEventPublisher;
+
+
+ public Response execute(AddCustomerCmd cmd) {
+ logger.info("Start processing command:" + cmd);
+
+ //validation
+ extensionExecutor.executeVoid(AddCustomerValidatorExtPt.class, cmd.getBizScenario(), extension -> extension.validate(cmd));
+
+ //Convert CO to Entity
+ CustomerEntity customerEntity = extensionExecutor.execute(CustomerConvertorExtPt.class, cmd.getBizScenario(), extension -> extension.clientToEntity(cmd));
+
+ //Call Domain Entity for business logic processing
+ logger.info("Call Domain Entity for business logic processing..."+customerEntity);
+ customerEntity.addNewCustomer();
+
+ domainEventPublisher.publish(new CustomerCreatedEvent());
+ logger.info("End processing command:" + cmd);
+ return Response.buildSuccess();
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/Constants.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/Constants.java
new file mode 100644
index 000000000..900daf966
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/Constants.java
@@ -0,0 +1,22 @@
+package com.alibaba.cola.test.customer;
+
+/**
+ * Constants
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 1:23 AM
+ */
+public class Constants {
+
+ public static final String BIZ_1 = "BIZ_ONE";
+ public static final String BIZ_2 = "BIZ_TWO";
+
+ public static final String TENANT_ID = "122344";
+
+
+ public static final String SOURCE_AD = "Advertisement";
+ public static final String SOURCE_WB = "Web site";
+ public static final String SOURCE_RFQ = "Request For Quota";
+ public static final String SOURCE_MARKETING = "Marketing";
+ public static final String SOURCE_OFFLINE = "Off Line";
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCO.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCO.java
new file mode 100644
index 000000000..d80cbe437
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCO.java
@@ -0,0 +1,40 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.dto.ClientObject;
+
+
+/**
+ * CustomerCO
+ *
+ * @author Frank Zhang 2018-01-06 7:30 PM
+ */
+public class CustomerCO extends ClientObject{
+
+ private String companyName;
+ private String source; //advertisement, p4p, RFQ, ATM
+ private CustomerType customerType; //potential, intentional, important, vip
+
+ public String getCompanyName() {
+ return companyName;
+ }
+
+ public void setCompanyName(String companyName) {
+ this.companyName = companyName;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public CustomerType getCustomerType() {
+ return customerType;
+ }
+
+ public void setCustomerType(CustomerType customerType) {
+ this.customerType = customerType;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCreatedEvent.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCreatedEvent.java
new file mode 100644
index 000000000..9ef3b9e93
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCreatedEvent.java
@@ -0,0 +1,12 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.event.DomainEventI;
+
+/**
+ * CustomerCreatedEvent
+ *
+ * @author Frank Zhang
+ * @date 2020-06-22 6:59 PM
+ */
+public class CustomerCreatedEvent implements DomainEventI {
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCreatedEventHandler.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCreatedEventHandler.java
new file mode 100644
index 000000000..7269251c7
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerCreatedEventHandler.java
@@ -0,0 +1,22 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.event.EventHandler;
+import com.alibaba.cola.event.EventHandlerI;
+import com.alibaba.cola.event.EventI;
+
+/**
+ * CustomerCreatedEventHandler
+ *
+ * @author Frank Zhang
+ * @date 2020-06-22 7:00 PM
+ */
+@EventHandler
+public class CustomerCreatedEventHandler implements EventHandlerI {
+
+ @Override
+ public Response execute(CustomerCreatedEvent customerCreatedEvent) {
+ System.out.println("customerCreatedEvent processed");
+ return null;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerDO.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerDO.java
new file mode 100644
index 000000000..2b79c3283
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerDO.java
@@ -0,0 +1,65 @@
+package com.alibaba.cola.test.customer;
+
+/**
+ * CustomerDO
+ *
+ * @author Frank Zhang
+ * @date 2018-01-08 1:45 PM
+ */
+
+public class CustomerDO implements java.io.Serializable {
+ private String customerId;
+ private String memberId;
+ private String globalId;
+ private String companyName;
+ private String source;
+ private String companyType;
+
+ public String getCustomerId() {
+ return customerId;
+ }
+
+ public void setCustomerId(String customerId) {
+ this.customerId = customerId;
+ }
+
+ public String getMemberId() {
+ return memberId;
+ }
+
+ public void setMemberId(String memberId) {
+ this.memberId = memberId;
+ }
+
+ public String getGlobalId() {
+ return globalId;
+ }
+
+ public void setGlobalId(String globalId) {
+ this.globalId = globalId;
+ }
+
+ public String getCompanyName() {
+ return companyName;
+ }
+
+ public void setCompanyName(String companyName) {
+ this.companyName = companyName;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getCompanyType() {
+ return companyType;
+ }
+
+ public void setCompanyType(String companyType) {
+ this.companyType = companyType;
+ }
+}
\ No newline at end of file
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerServiceI.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerServiceI.java
new file mode 100644
index 000000000..313cd1dff
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerServiceI.java
@@ -0,0 +1,14 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.dto.SingleResponse;
+
+/**
+ * CustomerServiceI
+ *
+ * @author Frank Zhang 2018-01-06 7:24 PM
+ */
+public interface CustomerServiceI {
+ public Response addCustomer(AddCustomerCmd addCustomerCmd);
+ public SingleResponse getCustomer(GetOneCustomerQry getOneCustomerQry);
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerServiceImpl.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerServiceImpl.java
new file mode 100644
index 000000000..b3a1f9f79
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerServiceImpl.java
@@ -0,0 +1,33 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.dto.SingleResponse;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * CustomerServiceImpl
+ *
+ * @author Frank Zhang 2018-01-06 7:40 PM
+ */
+@Service
+public class CustomerServiceImpl implements CustomerServiceI{
+
+ @Resource
+ private AddCustomerCmdExe addCustomerCmdExe;
+
+ @Resource
+ private GetOneCustomerQryExe getOneCustomerQryExe;
+
+
+ @Override
+ public Response addCustomer(AddCustomerCmd addCustomerCmd) {
+ return addCustomerCmdExe.execute(addCustomerCmd);
+ }
+
+ @Override
+ public SingleResponse getCustomer(GetOneCustomerQry getOneCustomerQry) {
+ return getOneCustomerQryExe.execute(getOneCustomerQry);
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerType.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerType.java
new file mode 100644
index 000000000..67f0669e4
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/CustomerType.java
@@ -0,0 +1,13 @@
+package com.alibaba.cola.test.customer;
+
+/**
+ * CustomerType
+ *
+ * @author Frank Zhang 2018-01-06 7:35 PM
+ */
+public enum CustomerType {
+ POTENTIAL,
+ INTENTIONAL,
+ IMPORTANT,
+ VIP;
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/DomainEventPublisher.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/DomainEventPublisher.java
new file mode 100644
index 000000000..992699c3d
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/DomainEventPublisher.java
@@ -0,0 +1,23 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.event.DomainEventI;
+import com.alibaba.cola.event.EventBusI;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * DomainEventPublisher
+ *
+ * @author Frank Zhang
+ * @date 2020-06-22 7:04 PM
+ */
+@Component
+public class DomainEventPublisher {
+ @Resource
+ private EventBusI eventBus;
+
+ public void publish(DomainEventI domainEvent) {
+ eventBus.fire(domainEvent);
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/GetOneCustomerQry.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/GetOneCustomerQry.java
new file mode 100644
index 000000000..9eab312d3
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/GetOneCustomerQry.java
@@ -0,0 +1,29 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.dto.Query;
+
+/**
+ * GetOneCustomerQry
+ *
+ * @author Frank Zhang 2018-01-06 7:38 PM
+ */
+public class GetOneCustomerQry extends Query{
+ private long customerId;
+ private String companyName;
+
+ public long getCustomerId() {
+ return customerId;
+ }
+
+ public void setCustomerId(long customerId) {
+ this.customerId = customerId;
+ }
+
+ public String getCompanyName() {
+ return companyName;
+ }
+
+ public void setCompanyName(String companyName) {
+ this.companyName = companyName;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/GetOneCustomerQryExe.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/GetOneCustomerQryExe.java
new file mode 100644
index 000000000..18223008f
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/GetOneCustomerQryExe.java
@@ -0,0 +1,18 @@
+package com.alibaba.cola.test.customer;
+
+import com.alibaba.cola.dto.SingleResponse;
+import org.springframework.stereotype.Component;
+
+/**
+ * GetOneCustomerQryExe
+ *
+ * @author Frank Zhang
+ * @date 2020-06-22 5:12 PM
+ */
+@Component
+public class GetOneCustomerQryExe {
+
+ public SingleResponse execute(GetOneCustomerQry getOneCustomerQry){
+ return null;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerBizOneConvertorExt.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerBizOneConvertorExt.java
new file mode 100644
index 000000000..5371cd8c7
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerBizOneConvertorExt.java
@@ -0,0 +1,37 @@
+package com.alibaba.cola.test.customer.convertor;
+
+import com.alibaba.cola.extension.Extension;
+import com.alibaba.cola.test.customer.AddCustomerCmd;
+import com.alibaba.cola.test.customer.Constants;
+import com.alibaba.cola.test.customer.CustomerCO;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+import com.alibaba.cola.test.customer.entity.SourceType;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * CustomerBizOneConvertorExt
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 3:05 AM
+ */
+@Extension(bizId = Constants.BIZ_1)
+public class CustomerBizOneConvertorExt implements CustomerConvertorExtPt{
+
+ @Autowired
+ private CustomerConvertor customerConvertor;//Composite basic convertor to do basic conversion
+
+ @Override
+ public CustomerEntity clientToEntity(AddCustomerCmd addCustomerCmd){
+ CustomerEntity customerEntity = customerConvertor.clientToEntity(addCustomerCmd);
+ CustomerCO customerCO=addCustomerCmd.getCustomerCO();
+ //In this business, AD and RFQ are regarded as different source
+ if(Constants.SOURCE_AD.equals(customerCO.getSource()))
+ {
+ customerEntity.setSourceType(SourceType.AD);
+ }
+ if (Constants.SOURCE_RFQ.equals(customerCO.getSource())){
+ customerEntity.setSourceType(SourceType.RFQ);
+ }
+ return customerEntity;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerBizTwoConvertorExt.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerBizTwoConvertorExt.java
new file mode 100644
index 000000000..3fe87ccbe
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerBizTwoConvertorExt.java
@@ -0,0 +1,33 @@
+package com.alibaba.cola.test.customer.convertor;
+
+import com.alibaba.cola.extension.Extension;
+import com.alibaba.cola.test.customer.AddCustomerCmd;
+import com.alibaba.cola.test.customer.Constants;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+import com.alibaba.cola.test.customer.entity.SourceType;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * CustomerBizTwoConvertorExt
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 3:05 AM
+ */
+@Extension(bizId = Constants.BIZ_2)
+public class CustomerBizTwoConvertorExt implements CustomerConvertorExtPt{
+
+ @Autowired
+ private CustomerConvertor customerConvertor;//Composite basic convertor to do basic conversion
+
+ @Override
+ public CustomerEntity clientToEntity(AddCustomerCmd addCustomerCmd){
+ CustomerEntity customerEntity = customerConvertor.clientToEntity(addCustomerCmd);
+ //In this business, if customers from RFQ and Advertisement are both regarded as Advertisement
+ if(Constants.SOURCE_AD.equals(addCustomerCmd.getCustomerCO().getSource()) || Constants.SOURCE_RFQ.equals(addCustomerCmd.getCustomerCO().getSource()))
+ {
+ customerEntity.setSourceType(SourceType.AD);
+ }
+ return customerEntity;
+ }
+
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerConvertor.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerConvertor.java
new file mode 100644
index 000000000..01c7b7473
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerConvertor.java
@@ -0,0 +1,27 @@
+package com.alibaba.cola.test.customer.convertor;
+
+import com.alibaba.cola.common.ApplicationContextHelper;
+import com.alibaba.cola.test.customer.AddCustomerCmd;
+import com.alibaba.cola.test.customer.CustomerCO;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+import org.springframework.stereotype.Component;
+
+/**
+ * CustomerConvertor
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 3:08 AM
+ */
+@Component
+public class CustomerConvertor{
+
+ public CustomerEntity clientToEntity(Object clientObject){
+ AddCustomerCmd addCustomerCmd = (AddCustomerCmd)clientObject;
+ CustomerCO customerCO=addCustomerCmd.getCustomerCO();
+ CustomerEntity customerEntity = (CustomerEntity)ApplicationContextHelper.getBean(CustomerEntity.class);
+ customerEntity.setCompanyName(customerCO.getCompanyName());
+ customerEntity.setCustomerType(customerCO.getCustomerType());
+ customerEntity.setBizScenario(addCustomerCmd.getBizScenario());
+ return customerEntity;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerConvertorExtPt.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerConvertorExtPt.java
new file mode 100644
index 000000000..2de901d0e
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/convertor/CustomerConvertorExtPt.java
@@ -0,0 +1,16 @@
+package com.alibaba.cola.test.customer.convertor;
+
+import com.alibaba.cola.extension.ExtensionPointI;
+import com.alibaba.cola.test.customer.AddCustomerCmd;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+
+/**
+ * CustomerConvertorExtPt
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 2:37 AM
+ */
+public interface CustomerConvertorExtPt extends ExtensionPointI {
+
+ public CustomerEntity clientToEntity(AddCustomerCmd addCustomerCmd);
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/CustomerEntity.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/CustomerEntity.java
new file mode 100644
index 000000000..1c0fd80a4
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/CustomerEntity.java
@@ -0,0 +1,65 @@
+package com.alibaba.cola.test.customer.entity;
+
+import com.alibaba.cola.domain.Entity;
+import com.alibaba.cola.domain.EntityObject;
+import com.alibaba.cola.extension.ExtensionExecutor;
+import com.alibaba.cola.test.customer.CustomerType;
+import com.alibaba.cola.test.customer.entity.rule.CustomerRuleExtPt;
+import com.alibaba.cola.test.customer.repository.CustomerRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Customer Entity
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 2:38 AM
+ */
+@Entity
+public class CustomerEntity extends EntityObject {
+
+ private String companyName;
+ private SourceType sourceType;
+ private CustomerType customerType;
+
+ @Autowired
+ private CustomerRepository customerRepository;
+ @Autowired
+ private ExtensionExecutor extensionExecutor;
+
+ public CustomerEntity() {
+
+ }
+
+ public void addNewCustomer() {
+ //Add customer policy
+ extensionExecutor.execute(CustomerRuleExtPt.class,this.getBizScenario(), extension -> extension.addCustomerCheck(this));
+
+ //Persist customer
+ customerRepository.persist(this);
+
+ }
+
+ public String getCompanyName() {
+ return companyName;
+ }
+
+ public void setCompanyName(String companyName) {
+ this.companyName = companyName;
+ }
+
+ public SourceType getSourceType() {
+ return sourceType;
+ }
+
+ public void setSourceType(SourceType sourceType) {
+ this.sourceType = sourceType;
+ }
+
+ public CustomerType getCustomerType() {
+ return customerType;
+ }
+
+ public void setCustomerType(CustomerType customerType) {
+ this.customerType = customerType;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/SourceType.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/SourceType.java
new file mode 100644
index 000000000..8b4062dfb
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/SourceType.java
@@ -0,0 +1,13 @@
+package com.alibaba.cola.test.customer.entity;
+
+/**
+ * SourceType
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 3:02 AM
+ */
+public enum SourceType {
+ AD, //Advertisement 广告
+ WB, // Web site 网站
+ RFQ; // Request For Quota 询盘
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerBizOneRuleExt.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerBizOneRuleExt.java
new file mode 100644
index 000000000..74ce15b2e
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerBizOneRuleExt.java
@@ -0,0 +1,25 @@
+package com.alibaba.cola.test.customer.entity.rule;
+
+import com.alibaba.cola.exception.BizException;
+import com.alibaba.cola.extension.Extension;
+import com.alibaba.cola.test.customer.Constants;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+import com.alibaba.cola.test.customer.entity.SourceType;
+
+/**
+ * CustomerBizOneRuleExt
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 12:10 PM
+ */
+@Extension(bizId = Constants.BIZ_1)
+public class CustomerBizOneRuleExt implements CustomerRuleExtPt{
+
+ @Override
+ public boolean addCustomerCheck(CustomerEntity customerEntity) {
+ if(SourceType.AD == customerEntity.getSourceType()){
+ throw new BizException("Sorry, Customer from advertisement can not be added in this period");
+ }
+ return true;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerBizTwoRuleExt.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerBizTwoRuleExt.java
new file mode 100644
index 000000000..653a3c7a0
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerBizTwoRuleExt.java
@@ -0,0 +1,21 @@
+package com.alibaba.cola.test.customer.entity.rule;
+
+import com.alibaba.cola.extension.Extension;
+import com.alibaba.cola.test.customer.Constants;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+
+/**
+ * CustomerBizTwoRuleExt
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 12:10 PM
+ */
+@Extension(bizId = Constants.BIZ_2)
+public class CustomerBizTwoRuleExt implements CustomerRuleExtPt{
+
+ @Override
+ public boolean addCustomerCheck(CustomerEntity customerEntity) {
+ //Any Customer can be added
+ return true;
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerRuleExtPt.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerRuleExtPt.java
new file mode 100644
index 000000000..5cc01cf49
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/entity/rule/CustomerRuleExtPt.java
@@ -0,0 +1,21 @@
+package com.alibaba.cola.test.customer.entity.rule;
+
+import com.alibaba.cola.extension.ExtensionPointI;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+
+/**
+ * CustomerRuleExtPt
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 12:03 PM
+ */
+public interface CustomerRuleExtPt extends ExtensionPointI{
+
+ //Different business check for different biz
+ public boolean addCustomerCheck(CustomerEntity customerEntity);
+
+ //Different upgrade policy for different biz
+ default public void customerUpgradePolicy(CustomerEntity customerEntity){
+ //Nothing special
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/repository/CustomerRepository.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/repository/CustomerRepository.java
new file mode 100644
index 000000000..c0a980824
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/repository/CustomerRepository.java
@@ -0,0 +1,18 @@
+package com.alibaba.cola.test.customer.repository;
+
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+import org.springframework.stereotype.Repository;
+
+/**
+ * CustomerRepository
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 11:59 AM
+ */
+@Repository
+public class CustomerRepository {
+
+ public void persist(CustomerEntity customerEntity){
+ System.out.println("Persist customer to DB : "+ customerEntity);
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extension/AddCustomerBizOneValidator.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extension/AddCustomerBizOneValidator.java
new file mode 100644
index 000000000..b784fa4ea
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extension/AddCustomerBizOneValidator.java
@@ -0,0 +1,24 @@
+package com.alibaba.cola.test.customer.validator.extension;
+
+import com.alibaba.cola.exception.BizException;
+import com.alibaba.cola.extension.Extension;
+import com.alibaba.cola.test.customer.AddCustomerCmd;
+import com.alibaba.cola.test.customer.Constants;
+import com.alibaba.cola.test.customer.CustomerType;
+import com.alibaba.cola.test.customer.validator.extensionpoint.AddCustomerValidatorExtPt;
+
+/**
+ * AddCustomerBizOneValidator
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 1:31 AM
+ */
+@Extension(bizId = Constants.BIZ_1)
+public class AddCustomerBizOneValidator implements AddCustomerValidatorExtPt{
+
+ public void validate(AddCustomerCmd addCustomerCmd) {
+ //For BIZ TWO CustomerTYpe could not be VIP
+ if(CustomerType.VIP == addCustomerCmd.getCustomerCO().getCustomerType())
+ throw new BizException("Customer Type could not be VIP for Biz One");
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extension/AddCustomerBizTwoValidator.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extension/AddCustomerBizTwoValidator.java
new file mode 100644
index 000000000..320660515
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extension/AddCustomerBizTwoValidator.java
@@ -0,0 +1,23 @@
+package com.alibaba.cola.test.customer.validator.extension;
+
+import com.alibaba.cola.exception.BizException;
+import com.alibaba.cola.extension.Extension;
+import com.alibaba.cola.test.customer.AddCustomerCmd;
+import com.alibaba.cola.test.customer.Constants;
+import com.alibaba.cola.test.customer.validator.extensionpoint.AddCustomerValidatorExtPt;
+
+/**
+ * AddCustomerBizTwoValidator
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 1:31 AM
+ */
+@Extension(bizId = Constants.BIZ_2)
+public class AddCustomerBizTwoValidator implements AddCustomerValidatorExtPt{
+
+ public void validate(AddCustomerCmd addCustomerCmd) {
+ //For BIZ TWO CustomerTYpe could not be null
+ if (addCustomerCmd.getCustomerCO().getCustomerType() == null)
+ throw new BizException("CustomerType could not be null");
+ }
+}
diff --git a/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extensionpoint/AddCustomerValidatorExtPt.java b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extensionpoint/AddCustomerValidatorExtPt.java
new file mode 100644
index 000000000..0a5637353
--- /dev/null
+++ b/cola-framework-core/src/test/java/com/alibaba/cola/test/customer/validator/extensionpoint/AddCustomerValidatorExtPt.java
@@ -0,0 +1,16 @@
+package com.alibaba.cola.test.customer.validator.extensionpoint;
+
+import com.alibaba.cola.extension.ExtensionPointI;
+import com.alibaba.cola.test.customer.AddCustomerCmd;
+import com.alibaba.cola.test.customer.entity.CustomerEntity;
+
+/**
+ * AddCustomerValidatorExtPt
+ *
+ * @author Frank Zhang
+ * @date 2018-01-07 1:27 AM
+ */
+public interface AddCustomerValidatorExtPt extends ExtensionPointI {
+
+ public void validate(AddCustomerCmd addCustomerCmd);
+}
diff --git a/cola-framework-core/src/test/resources/sample.properties b/cola-framework-core/src/test/resources/sample.properties
new file mode 100644
index 000000000..9c246053e
--- /dev/null
+++ b/cola-framework-core/src/test/resources/sample.properties
@@ -0,0 +1 @@
+bizCode=BIZ_ONE