Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
asset-distribution
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
data-spider
asset-distribution
Commits
89aebf3b
Commit
89aebf3b
authored
Jul 26, 2019
by
liwenbin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
资产分发初始化代码
parent
bc98d9e1
Changes
63
Hide whitespace changes
Inline
Side-by-side
Showing
63 changed files
with
4314 additions
and
128 deletions
+4314
-128
pom.xml
pom.xml
+11
-0
DataSourceConfig.java
...sset/distribution/config/datasource/DataSourceConfig.java
+97
-0
AuthorityInterceptor.java
...ribution/config/web/interceptor/AuthorityInterceptor.java
+1
-1
AssetAttributeConstants.java
.../asset/distribution/constant/AssetAttributeConstants.java
+20
-0
DistributeConstants.java
...roup/asset/distribution/constant/DistributeConstants.java
+32
-0
DistributeLogoConstants.java
.../asset/distribution/constant/DistributeLogoConstants.java
+19
-0
RedisKeyConstants.java
...tgroup/asset/distribution/constant/RedisKeyConstants.java
+5
-0
StatusConstants.java
...antgroup/asset/distribution/constant/StatusConstants.java
+13
-0
AssetController.java
...tgroup/asset/distribution/controller/AssetController.java
+10
-6
RedisFlushController.java
...p/asset/distribution/controller/RedisFlushController.java
+25
-8
AssetResponse.java
...roup/asset/distribution/enums/response/AssetResponse.java
+1
-0
QGExceptionType.java
...ntgroup/asset/distribution/exception/QGExceptionType.java
+8
-1
DistributeRecord.java
...oup/asset/distribution/model/entity/DistributeRecord.java
+43
-0
Record.java
...om/quantgroup/asset/distribution/model/entity/Record.java
+26
-0
AssetForm.java
...m/quantgroup/asset/distribution/model/form/AssetForm.java
+25
-0
IAlarmService.java
...group/asset/distribution/service/alarm/IAlarmService.java
+18
-0
AlarmServiceImpl.java
...set/distribution/service/alarm/impl/AlarmServiceImpl.java
+49
-0
IAssetAttributeExtendConfigService.java
...ion/service/asset/IAssetAttributeExtendConfigService.java
+24
-0
IAssetAttributeService.java
...et/distribution/service/asset/IAssetAttributeService.java
+11
-4
IAssetService.java
...group/asset/distribution/service/asset/IAssetService.java
+2
-3
AssetAttributeExtendConfigServiceImpl.java
...ice/asset/impl/AssetAttributeExtendConfigServiceImpl.java
+37
-0
AssetAttributeServiceImpl.java
...ibution/service/asset/impl/AssetAttributeServiceImpl.java
+122
-0
AssetServiceImpl.java
...set/distribution/service/asset/impl/AssetServiceImpl.java
+137
-0
IAuthorityService.java
...set/distribution/service/authority/IAuthorityService.java
+1
-1
AuthorityServiceImpl.java
...ribution/service/authority/impl/AuthorityServiceImpl.java
+4
-5
IAssetDistributeRecordService.java
...ion/service/distribute/IAssetDistributeRecordService.java
+30
-0
IAssetDistributeRuleConfigService.java
...service/distribute/IAssetDistributeRuleConfigService.java
+17
-0
IAssetDistributeService.java
...tribution/service/distribute/IAssetDistributeService.java
+23
-0
IDistributeFailLogService.java
...ibution/service/distribute/IDistributeFailLogService.java
+18
-0
AssetDistributeRecordServiceImpl.java
...ice/distribute/impl/AssetDistributeRecordServiceImpl.java
+62
-0
AssetDistributeRuleConfigServiceImpl.java
...distribute/impl/AssetDistributeRuleConfigServiceImpl.java
+36
-0
AssetDistributeServiceImpl.java
...n/service/distribute/impl/AssetDistributeServiceImpl.java
+178
-0
DistributeFailLogServiceImpl.java
...service/distribute/impl/DistributeFailLogServiceImpl.java
+41
-0
AssetServiceImpl.java
...oup/asset/distribution/service/impl/AssetServiceImpl.java
+0
-91
Asset.java
...antgroup/asset/distribution/service/jpa/entity/Asset.java
+7
-1
AssetAttributeExtend.java
...distribution/service/jpa/entity/AssetAttributeExtend.java
+7
-1
AssetAttributeExtendConfig.java
...bution/service/jpa/entity/AssetAttributeExtendConfig.java
+8
-2
AssetDistributeRecord.java
...istribution/service/jpa/entity/AssetDistributeRecord.java
+84
-0
AssetDistributeRuleConfig.java
...ibution/service/jpa/entity/AssetDistributeRuleConfig.java
+81
-0
AuthorityConfig.java
...sset/distribution/service/jpa/entity/AuthorityConfig.java
+8
-2
DistributeFailLog.java
...et/distribution/service/jpa/entity/DistributeFailLog.java
+79
-0
IAssetAttributeExtendConfigRepository.java
...jpa/repository/IAssetAttributeExtendConfigRepository.java
+1
-1
IAssetDistributeRecordRepository.java
...vice/jpa/repository/IAssetDistributeRecordRepository.java
+17
-0
IAssetDistributeRuleConfigRepository.java
.../jpa/repository/IAssetDistributeRuleConfigRepository.java
+21
-0
IAuthorityRepository.java
...ribution/service/jpa/repository/IAuthorityRepository.java
+1
-1
IDistributeFailLogRepository.java
.../service/jpa/repository/IDistributeFailLogRepository.java
+14
-0
INotifyService.java
...oup/asset/distribution/service/notify/INotifyService.java
+17
-0
NotifyServiceImpl.java
...t/distribution/service/notify/impl/NotifyServiceImpl.java
+50
-0
IRuleService.java
...ntgroup/asset/distribution/service/rule/IRuleService.java
+14
-0
RuleServiceImpl.java
...asset/distribution/service/rule/impl/RuleServiceImpl.java
+49
-0
AbstractFunction.java
...tgroup/asset/distribution/util/calc/AbstractFunction.java
+86
-0
AbstractLazyFunction.java
...up/asset/distribution/util/calc/AbstractLazyFunction.java
+96
-0
AbstractLazyOperator.java
...up/asset/distribution/util/calc/AbstractLazyOperator.java
+102
-0
AbstractOperator.java
...tgroup/asset/distribution/util/calc/AbstractOperator.java
+63
-0
AbstractUnaryOperator.java
...p/asset/distribution/util/calc/AbstractUnaryOperator.java
+75
-0
Expression.java
...m/quantgroup/asset/distribution/util/calc/Expression.java
+1948
-0
Function.java
...com/quantgroup/asset/distribution/util/calc/Function.java
+45
-0
LazyFunction.java
...quantgroup/asset/distribution/util/calc/LazyFunction.java
+79
-0
LazyOperator.java
...quantgroup/asset/distribution/util/calc/LazyOperator.java
+72
-0
Operator.java
...com/quantgroup/asset/distribution/util/calc/Operator.java
+43
-0
AuthorityTest.java
...uantgroup/asset/distribution/authority/AuthorityTest.java
+32
-0
DistributeTest.java
...ntgroup/asset/distribution/distribute/DistributeTest.java
+41
-0
RuleValidTest.java
...com/quantgroup/asset/distribution/rule/RuleValidTest.java
+28
-0
No files found.
pom.xml
View file @
89aebf3b
...
@@ -320,6 +320,17 @@
...
@@ -320,6 +320,17 @@
<artifactId>
protobuf-java-format
</artifactId>
<artifactId>
protobuf-java-format
</artifactId>
<version>
1.3
</version>
<version>
1.3
</version>
</dependency>
</dependency>
<dependency>
<groupId>
com.udojava
</groupId>
<artifactId>
EvalEx
</artifactId>
<version>
2.1
</version>
</dependency>
<dependency>
<groupId>
com.alibaba
</groupId>
<artifactId>
druid
</artifactId>
<version>
1.1.10
</version>
</dependency>
</dependencies>
</dependencies>
</project>
</project>
src/main/java/com/quantgroup/asset/distribution/config/datasource/DataSourceConfig.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
config
.
datasource
;
import
java.sql.SQLException
;
import
javax.sql.DataSource
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Primary
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
com.alibaba.druid.pool.DruidDataSource
;
/**
* 数据库配置
* @author liwenbin
*
*/
@Configuration
public
class
DataSourceConfig
{
@Value
(
"${spring.datasource.primary.url}"
)
private
String
dbUrl
;
@Value
(
"${spring.datasource.primary.username}"
)
private
String
username
;
@Value
(
"${spring.datasource.primary.password}"
)
private
String
password
;
@Value
(
"${spring.datasource.primary.driver-class-name}"
)
private
String
driverClassName
;
@Value
(
"${spring.datasource.initialSize}"
)
private
int
initialSize
;
@Value
(
"${spring.datasource.minIdle}"
)
private
int
minIdle
;
@Value
(
"${spring.datasource.maxActive}"
)
private
int
maxActive
;
@Value
(
"${spring.datasource.maxWait}"
)
private
int
maxWait
;
@Value
(
"${spring.datasource.timeBetweenEvictionRunsMillis}"
)
private
int
timeBetweenEvictionRunsMillis
;
@Value
(
"${spring.datasource.minEvictableIdleTimeMillis}"
)
private
int
minEvictableIdleTimeMillis
;
@Value
(
"${spring.datasource.validationQuery}"
)
private
String
validationQuery
;
@Value
(
"${spring.datasource.testWhileIdle}"
)
private
boolean
testWhileIdle
;
@Value
(
"${spring.datasource.testOnBorrow}"
)
private
boolean
testOnBorrow
;
@Value
(
"${spring.datasource.testOnReturn}"
)
private
boolean
testOnReturn
;
@Value
(
"${spring.datasource.poolPreparedStatements}"
)
private
boolean
poolPreparedStatements
;
@Value
(
"${spring.datasource.maxPoolPreparedStatementPerConnectionSize}"
)
private
int
maxPoolPreparedStatementPerConnectionSize
;
@Value
(
"${spring.datasource.filters}"
)
private
String
filters
;
@Value
(
"{spring.datasource.connectionProperties}"
)
private
String
connectionProperties
;
@Bean
@Primary
public
DataSource
primaryDataSource
()
throws
SQLException
{
DruidDataSource
datasource
=
new
DruidDataSource
();
datasource
.
setUrl
(
dbUrl
);
datasource
.
setUsername
(
username
);
datasource
.
setPassword
(
password
);
datasource
.
setDriverClassName
(
driverClassName
);
datasource
.
setInitialSize
(
initialSize
);
datasource
.
setMinIdle
(
minIdle
);
datasource
.
setMaxActive
(
maxActive
);
datasource
.
setMaxWait
(
maxWait
);
datasource
.
setTimeBetweenEvictionRunsMillis
(
timeBetweenEvictionRunsMillis
);
datasource
.
setMinEvictableIdleTimeMillis
(
minEvictableIdleTimeMillis
);
datasource
.
setValidationQuery
(
validationQuery
);
datasource
.
setTestWhileIdle
(
testWhileIdle
);
datasource
.
setTestOnBorrow
(
testOnBorrow
);
datasource
.
setTestOnReturn
(
testOnReturn
);
datasource
.
setPoolPreparedStatements
(
poolPreparedStatements
);
datasource
.
setMaxPoolPreparedStatementPerConnectionSize
(
maxPoolPreparedStatementPerConnectionSize
);
datasource
.
setFilters
(
filters
);
datasource
.
setConnectionProperties
(
connectionProperties
);
return
datasource
;
}
@Bean
public
JdbcTemplate
primaryJdbcTemplate
(
@Qualifier
(
"primaryDataSource"
)
DataSource
dataSource
)
{
return
new
JdbcTemplate
(
dataSource
);
}
}
src/main/java/com/quantgroup/asset/distribution/config/web/interceptor/AuthorityInterceptor.java
View file @
89aebf3b
...
@@ -11,7 +11,7 @@ import org.springframework.web.servlet.ModelAndView;
...
@@ -11,7 +11,7 @@ import org.springframework.web.servlet.ModelAndView;
import
com.quantgroup.asset.distribution.enums.response.AuthorityResponse
;
import
com.quantgroup.asset.distribution.enums.response.AuthorityResponse
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.service.IAuthorityService
;
import
com.quantgroup.asset.distribution.service.
authority.
IAuthorityService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAuthorityRepository
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAuthorityRepository
;
...
...
src/main/java/com/quantgroup/asset/distribution/constant/AssetAttributeConstants.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
constant
;
/**
* 资产属性特征key常量值
* @author liwenbin
*
*/
public
class
AssetAttributeConstants
{
/**
* 用户类型
*/
public
static
final
String
USER_LOAN_TYPE
=
"user_loan_type_latest"
;
/**
* 风控审核结果
*/
public
static
final
String
AUDIT_RESULT
=
"auditResult"
;
}
src/main/java/com/quantgroup/asset/distribution/constant/DistributeConstants.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
constant
;
/**
* 分发相关常量值
* @author liwenbin
*
*/
public
class
DistributeConstants
{
/**
* 分发规则类型常量
* @author liwenbin
*
*/
public
static
class
RuleType
{
/**
* 资金理由
*/
public
static
final
int
FUND_ROUTE
=
1
;
/**
* 助贷资金路由
*/
public
static
final
int
AID_FUND_ROUTE
=
2
;
/**
* 导流
*/
public
static
final
int
DIVERSION
=
3
;
}
}
src/main/java/com/quantgroup/asset/distribution/constant/DistributeLogoConstants.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
constant
;
/**
* 分发标识类型常量
* @author liwenbin
*
*/
public
class
DistributeLogoConstants
{
/**
* 首次分发或者异常重试
*/
public
static
final
Integer
FIRST
=
1
;
/**
* 回流
*/
public
static
final
Integer
BACK_FLOW
=
2
;
}
src/main/java/com/quantgroup/asset/distribution/constant/RedisKeyConstants.java
View file @
89aebf3b
...
@@ -21,4 +21,9 @@ public class RedisKeyConstants {
...
@@ -21,4 +21,9 @@ public class RedisKeyConstants {
* 助贷资金总金额限制缓存key
* 助贷资金总金额限制缓存key
*/
*/
public
final
static
String
AID_LOAN_ALL_AMOUNT_LIMIT_KEY
=
"AID.LOAN.ALL.AMOUNT.LIMIT.KEY.9QDBFD_"
;
public
final
static
String
AID_LOAN_ALL_AMOUNT_LIMIT_KEY
=
"AID.LOAN.ALL.AMOUNT.LIMIT.KEY.9QDBFD_"
;
/**
* 分发失败节点记录
*/
public
final
static
String
DISTRIBUTE_FAIL_TYPE_RECORD
=
"ASSET.DISTRIBUTE.DISTRIBUTE.FAIL.TYPE.KEY.8SAWNB_"
;
}
}
src/main/java/com/quantgroup/asset/distribution/constant/StatusConstants.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
constant
;
/**
* 状态常量
* @author liwenbin
*
*/
public
class
StatusConstants
{
public
static
final
Integer
SUCCESS
=
1
;
public
static
final
Integer
FAIL
=
0
;
}
src/main/java/com/quantgroup/asset/distribution/controller/AssetController.java
View file @
89aebf3b
...
@@ -2,6 +2,8 @@ package com.quantgroup.asset.distribution.controller;
...
@@ -2,6 +2,8 @@ package com.quantgroup.asset.distribution.controller;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeUnit
;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
...
@@ -11,7 +13,7 @@ import com.google.common.base.Stopwatch;
...
@@ -11,7 +13,7 @@ import com.google.common.base.Stopwatch;
import
com.quantgroup.asset.distribution.enums.response.AssetResponse
;
import
com.quantgroup.asset.distribution.enums.response.AssetResponse
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.service.IAssetService
;
import
com.quantgroup.asset.distribution.service.
asset.
IAssetService
;
import
com.quantgroup.asset.distribution.util.UUIDUtil
;
import
com.quantgroup.asset.distribution.util.UUIDUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
...
@@ -30,13 +32,15 @@ public class AssetController {
...
@@ -30,13 +32,15 @@ public class AssetController {
private
IAssetService
assetService
;
private
IAssetService
assetService
;
@RequestMapping
(
"/asset_in"
)
@RequestMapping
(
"/asset_in"
)
public
GlobalResponse
assetsIn
(
AssetForm
assetForm
)
{
public
GlobalResponse
assetsIn
(
AssetForm
assetForm
,
HttpServletRequest
request
)
{
Stopwatch
stopwatch
=
Stopwatch
.
createStarted
();
Stopwatch
stopwatch
=
Stopwatch
.
createStarted
();
assetForm
.
setAssetNo
(
UUIDUtil
.
getAssetNo
());
assetForm
.
setAssetNo
(
UUIDUtil
.
getAssetNo
());
log
.
info
(
"资产入库开始, assetForm : {}"
,
JSON
.
toJSONString
(
assetForm
));
String
authKey
=
request
.
getHeader
(
"as_auth_key"
);
GlobalResponse
response
=
assetService
.
checkAssetForm
(
assetForm
);
log
.
info
(
"资产入库分发开始, assetForm : {}, authKey : {}"
,
JSON
.
toJSONString
(
assetForm
),
authKey
);
boolean
check
=
assetService
.
checkAssetForm
(
assetForm
);
if
(!
check
)
{
return
GlobalResponse
.
create
(
AssetResponse
.
ASSET_FORM_IS_ERROR
);
}
assetService
.
assetsIn
(
assetForm
);
assetService
.
assetsIn
(
assetForm
);
log
.
info
(
"资产入库
结束, assetForm : {}, response : {}, 耗时 : {}"
,
JSON
.
toJSONString
(
assetForm
),
JSON
.
toJSONString
(
response
),
stopwatch
.
stop
().
elapsed
(
TimeUnit
.
MILLISECONDS
));
log
.
info
(
"资产入库
分发结束, assetForm : {}, authKey : {}, response : {}, 耗时 : {}"
,
JSON
.
toJSONString
(
assetForm
),
authKey
,
JSON
.
toJSONString
(
AssetResponse
.
SUCCESS
),
stopwatch
.
stop
().
elapsed
(
TimeUnit
.
MILLISECONDS
));
return
response
;
return
GlobalResponse
.
create
(
AssetResponse
.
SUCCESS
)
;
}
}
}
}
src/main/java/com/quantgroup/asset/distribution/controller/RedisFlushController.java
View file @
89aebf3b
...
@@ -2,6 +2,9 @@ package com.quantgroup.asset.distribution.controller;
...
@@ -2,6 +2,9 @@ package com.quantgroup.asset.distribution.controller;
import
com.quantgroup.asset.distribution.constant.RedisKeyConstants
;
import
com.quantgroup.asset.distribution.constant.RedisKeyConstants
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.service.asset.IAssetAttributeExtendConfigService
;
import
com.quantgroup.asset.distribution.service.authority.IAuthorityService
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRuleConfigService
;
import
com.quantgroup.asset.distribution.service.redis.IRedisService
;
import
com.quantgroup.asset.distribution.service.redis.IRedisService
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
@@ -24,6 +27,12 @@ public class RedisFlushController {
...
@@ -24,6 +27,12 @@ public class RedisFlushController {
@Autowired
@Autowired
private
IRedisService
<
String
>
redisService
;
private
IRedisService
<
String
>
redisService
;
@Autowired
private
IAssetAttributeExtendConfigService
assetAttributeExtendConfigService
;
@Autowired
private
IAuthorityService
authorityService
;
@Autowired
private
IAssetDistributeRuleConfigService
assetDistributeRuleConfigService
;
/**
/**
* 助贷资金池刷新
* 助贷资金池刷新
...
@@ -37,13 +46,21 @@ public class RedisFlushController {
...
@@ -37,13 +46,21 @@ public class RedisFlushController {
return
GlobalResponse
.
success
();
return
GlobalResponse
.
success
();
}
}
@RequestMapping
(
"/attribute_extend_config_flush"
)
public
GlobalResponse
attributeExtendConfigFlush
(
String
key
)
{
if
(
authKey
.
equals
(
key
))
{
assetAttributeExtendConfigService
.
clearAllExtendConfigCache
();
}
return
GlobalResponse
.
success
();
}
@RequestMapping
(
"/authority_flush"
)
public
GlobalResponse
authorityFlush
(
String
key
,
String
authKey
,
String
authPass
)
{
if
(
authKey
.
equals
(
key
))
{
authorityService
.
clearCacheByAuthKeyAndAuthPass
(
authKey
,
authPass
);
}
return
GlobalResponse
.
success
();
}
@RequestMapping
(
"/distribute_rule_config_flush"
)
public
GlobalResponse
distributeRuleConfigFlush
(
String
key
)
{
if
(
authKey
.
equals
(
key
))
{
assetDistributeRuleConfigService
.
clearRuleConfigCache
();
}
return
GlobalResponse
.
success
();
}
}
}
src/main/java/com/quantgroup/asset/distribution/enums/response/AssetResponse.java
View file @
89aebf3b
...
@@ -9,6 +9,7 @@ import lombok.Getter;
...
@@ -9,6 +9,7 @@ import lombok.Getter;
*/
*/
public
enum
AssetResponse
implements
GlobalResponseEnum
{
public
enum
AssetResponse
implements
GlobalResponseEnum
{
SUCCESS
(
0
,
"success"
),
ASSET_FORM_IS_ERROR
(
2001
,
"资产入库参数错误!"
);
ASSET_FORM_IS_ERROR
(
2001
,
"资产入库参数错误!"
);
@Getter
@Getter
...
...
src/main/java/com/quantgroup/asset/distribution/exception/QGExceptionType.java
View file @
89aebf3b
...
@@ -23,7 +23,14 @@ public enum QGExceptionType {
...
@@ -23,7 +23,14 @@ public enum QGExceptionType {
ASSET_IN_CODE_ERROR
(
2001
,
"资产入库code异常! uuid : %s, bizNo : %s, code : %s"
),
ASSET_IN_CODE_ERROR
(
2001
,
"资产入库code异常! uuid : %s, bizNo : %s, code : %s"
),
GET_DEC_ATTRIBUTE_VALUE_ERROR
(
2002
,
"获取决策资产属性值异常, uuid : %s, keys : %s"
),
GET_DEC_ATTRIBUTE_VALUE_ERROR
(
2002
,
"获取决策资产属性值异常, uuid : %s, keys : %s"
),
ASSET_ATTRIBUTE_IS_EMPTY
(
2003
,
"%s资产属性值为空"
);
ASSET_ATTRIBUTE_IS_EMPTY
(
2003
,
"%s资产属性值为空"
),
DISTRIBUTE_RULE_CONFIG_PRIORITY_IS_NOT_UNIQUE
(
2021
,
"资产分发规则优先级不唯一"
),
RULE_CALC_ERROR
(
2022
,
"规则计算出现错误, expression : %s"
),
RULE_CALC_UNKNOW_ERROR
(
2023
,
"规则计算出现未知异常, expression : %s"
),
RULE_CALC_UNKNOW_RESULT
(
2024
,
"规则判断出现未知结果,请联系管理人员, expression : %s"
),
UNKNOW_RULE_TYPE
(
2025
,
"未知的规则类型, %s"
),
NO_DISTRIBUTE_NODE
(
2026
,
"未找到分发节点, uuid : %s, assetNo %s, records : %s"
);
...
...
src/main/java/com/quantgroup/asset/distribution/model/entity/DistributeRecord.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
model
.
entity
;
import
java.io.Serializable
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
lombok.Data
;
@Data
public
class
DistributeRecord
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
private
Map
<
String
,
Object
>
data
;
private
List
<
Record
>
records
;
public
DistributeRecord
(
Map
<
String
,
Object
>
data
)
{
this
.
data
=
data
;
records
=
new
ArrayList
<>();
}
public
void
addRecords
(
Long
id
,
String
expression
,
Integer
type
,
String
name
,
Boolean
valid
)
{
Record
record
=
new
Record
();
record
.
setId
(
id
);
record
.
setExpression
(
expression
);
record
.
setType
(
type
);
record
.
setName
(
name
);
record
.
setValid
(
valid
);
if
(
records
==
null
)
{
records
=
new
ArrayList
<>();
}
records
.
add
(
record
);
}
public
void
clearRecords
()
{
records
.
clear
();
}
}
src/main/java/com/quantgroup/asset/distribution/model/entity/Record.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
model
.
entity
;
import
java.io.Serializable
;
import
lombok.Data
;
@Data
public
class
Record
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
private
Long
id
;
private
String
expression
;
// 1-资金路由2-助贷3-导流
private
Integer
type
;
private
String
name
;
private
Boolean
valid
;
}
src/main/java/com/quantgroup/asset/distribution/model/form/AssetForm.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
model
.
form
;
package
com
.
quantgroup
.
asset
.
distribution
.
model
.
form
;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
java.util.HashMap
;
import
java.util.Map
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
...
@@ -42,6 +44,8 @@ public class AssetForm implements Serializable{
...
@@ -42,6 +44,8 @@ public class AssetForm implements Serializable{
private
String
callbackUrl
;
private
String
callbackUrl
;
private
int
repeatCount
=
0
;
public
Asset
transToAsset
()
{
public
Asset
transToAsset
()
{
Asset
asset
=
new
Asset
();
Asset
asset
=
new
Asset
();
asset
.
setAssetNo
(
this
.
assetNo
);
asset
.
setAssetNo
(
this
.
assetNo
);
...
@@ -54,4 +58,25 @@ public class AssetForm implements Serializable{
...
@@ -54,4 +58,25 @@ public class AssetForm implements Serializable{
return
asset
;
return
asset
;
}
}
/**
* 获取通知资金系统FormMap
* @return
*/
public
Map
<
String
,
String
>
transToNotifyMap
()
{
Map
<
String
,
String
>
notifyMap
=
new
HashMap
<>();
notifyMap
.
put
(
"code"
,
this
.
code
);
notifyMap
.
put
(
"msg"
,
this
.
msg
);
notifyMap
.
put
(
"uuid"
,
this
.
uuid
);
notifyMap
.
put
(
"bizChannel"
,
this
.
bizChannel
);
notifyMap
.
put
(
"bizNo"
,
this
.
bizNo
);
notifyMap
.
put
(
"bizType"
,
this
.
bizType
);
notifyMap
.
put
(
"auditResult"
,
this
.
auditResult
);
notifyMap
.
put
(
"amount"
,
this
.
amount
);
notifyMap
.
put
(
"deadLine"
,
this
.
deadLine
);
notifyMap
.
put
(
"exData"
,
this
.
exData
);
notifyMap
.
put
(
"otherInformation"
,
this
.
otherInformation
);
notifyMap
.
put
(
"financeProducts"
,
this
.
financeProducts
);
return
notifyMap
;
}
}
}
src/main/java/com/quantgroup/asset/distribution/service/alarm/IAlarmService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
alarm
;
/**
* 报警接口
* @author liwenbin
*
*/
public
interface
IAlarmService
{
/**
* 钉钉机器人报警
* @param webhook
* @param alarmLevel
* @param msgTitle
* @param msgContent
*/
public
void
dingtalkAlarm
(
String
alarmLevel
,
String
msgTitle
,
String
msgContent
);
}
src/main/java/com/quantgroup/asset/distribution/service/alarm/impl/AlarmServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
alarm
.
impl
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
com.quantgroup.asset.distribution.service.alarm.IAlarmService
;
import
com.quantgroup.asset.distribution.service.httpclient.IHttpService
;
import
lombok.extern.slf4j.Slf4j
;
/**
* 报警接口
* @author liwenbin
*
*/
@Slf4j
@Service
public
class
AlarmServiceImpl
implements
IAlarmService
{
private
static
final
String
ALARM_HTTP_URL
=
"http://alertserv-dataservice.quantgroup.cn/common/alert/dingtalk"
;
private
static
final
String
ROBOT_WEB_HOOK
=
"https://oapi.dingtalk.com/robot/send?access_token=53a55ffe3d4a5398a7ba44e4fcee1a3ac006edcba9cfdc4b1f9f692ffc18a5b8"
;
@Value
(
"${isDebug}"
)
private
Boolean
isDebug
;
@Autowired
private
IHttpService
httpService
;
@Async
@Override
public
void
dingtalkAlarm
(
String
alarmLevel
,
String
msgTitle
,
String
msgContent
)
{
try
{
// TODO
if
(
isDebug
)
{
return
;
}
Map
<
String
,
String
>
params
=
new
HashMap
<>();
params
.
put
(
"webhook"
,
ROBOT_WEB_HOOK
);
params
.
put
(
"alarmLevel"
,
alarmLevel
);
params
.
put
(
"msgTitle"
,
msgTitle
);
params
.
put
(
"msgContent"
,
msgContent
);
httpService
.
postNoResponse
(
ALARM_HTTP_URL
,
params
);
}
catch
(
Exception
e
)
{
log
.
error
(
"钉钉机器人报警异常, msg : {}"
,
msgContent
,
e
);
}
}
}
src/main/java/com/quantgroup/asset/distribution/service/asset/IAssetAttributeExtendConfigService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
asset
;
import
java.util.List
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
/**
* 资产扩展属性配置Service
* @author liwenbin
*
*/
public
interface
IAssetAttributeExtendConfigService
{
/**
* 获取所有可用的扩展属性配置
* @return
*/
public
List
<
AssetAttributeExtendConfig
>
getAllExtendConfig
();
/**
* 情书扩展属性配置缓存
*/
public
void
clearAllExtendConfigCache
();
}
src/main/java/com/quantgroup/asset/distribution/service/IAssetAttributeService.java
→
src/main/java/com/quantgroup/asset/distribution/service/
asset/
IAssetAttributeService.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
asset
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
/**
/**
...
@@ -13,13 +14,19 @@ import com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtend
...
@@ -13,13 +14,19 @@ import com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtend
*/
*/
public
interface
IAssetAttributeService
{
public
interface
IAssetAttributeService
{
// public List<AssetAttributeExtendConfig> getAllExtendCon
/**
/**
* 获取所有资产属性值
* 获取所有资产属性值
* @param assetAttributeExtendConfigList
* @param assetAttributeExtendConfigList
* @return
* @return
*/
*/
public
Map
<
String
,
Object
>
getAllAssetAttributeValue
(
List
<
AssetAttributeExtendConfig
>
assetAttributeExtendConfigList
,
AssetForm
assetForm
);
public
Map
<
String
,
Object
>
getAllAssetAttributeValue
(
List
<
AssetAttributeExtendConfig
>
assetAttributeExtendConfigList
,
AssetForm
assetForm
);
/**
* 资产入库
* @param asset
* @param assetAttributeExtendConfigList
* @param data
*/
public
void
saveAssetAttrubite
(
Asset
asset
,
List
<
AssetAttributeExtendConfig
>
assetAttributeExtendConfigList
,
Map
<
String
,
Object
>
data
);
}
}
src/main/java/com/quantgroup/asset/distribution/service/IAssetService.java
→
src/main/java/com/quantgroup/asset/distribution/service/
asset/
IAssetService.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
asset
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
/**
/**
* 资产Service
* 资产Service
...
@@ -22,5 +21,5 @@ public interface IAssetService {
...
@@ -22,5 +21,5 @@ public interface IAssetService {
* @param assetForm
* @param assetForm
* @return
* @return
*/
*/
public
GlobalResponse
checkAssetForm
(
AssetForm
assetForm
);
public
boolean
checkAssetForm
(
AssetForm
assetForm
);
}
}
src/main/java/com/quantgroup/asset/distribution/service/asset/impl/AssetAttributeExtendConfigServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
asset
.
impl
;
import
java.util.List
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cache.annotation.CacheEvict
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.stereotype.Service
;
import
com.quantgroup.asset.distribution.service.asset.IAssetAttributeExtendConfigService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAssetAttributeExtendConfigRepository
;
/**
* 资产扩展属性配置Service
* @author liwenbin
*
*/
@Service
public
class
AssetAttributeExtendConfigServiceImpl
implements
IAssetAttributeExtendConfigService
{
@Autowired
private
IAssetAttributeExtendConfigRepository
assetAttributeExtendConfigRepository
;
@Cacheable
(
value
=
"cacheManager"
,
key
=
"'ASSET_1023A_ALL_ATTRIBUTE_EXTEND_CONFIG'"
)
@Override
public
List
<
AssetAttributeExtendConfig
>
getAllExtendConfig
()
{
return
assetAttributeExtendConfigRepository
.
findByEnableIsTrue
();
}
@CacheEvict
(
value
=
"cacheManager"
,
key
=
"'ASSET_1023A_ALL_ATTRIBUTE_EXTEND_CONFIG'"
)
@Override
public
void
clearAllExtendConfigCache
()
{
}
}
src/main/java/com/quantgroup/asset/distribution/service/impl/AssetAttributeServiceImpl.java
→
src/main/java/com/quantgroup/asset/distribution/service/
asset/
impl/AssetAttributeServiceImpl.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
impl
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
asset
.
impl
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.HashSet
;
...
@@ -12,15 +12,21 @@ import org.apache.commons.lang3.StringUtils;
...
@@ -12,15 +12,21 @@ import org.apache.commons.lang3.StringUtils;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson.JSONObject
;
import
com.quantgroup.asset.distribution.constant.AssetAttributeConstants
;
import
com.quantgroup.asset.distribution.exception.QGExceptionType
;
import
com.quantgroup.asset.distribution.exception.QGExceptionType
;
import
com.quantgroup.asset.distribution.exception.QGPreconditions
;
import
com.quantgroup.asset.distribution.exception.QGPreconditions
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.service.IAssetAttributeService
;
import
com.quantgroup.asset.distribution.service.
asset.
IAssetAttributeService
;
import
com.quantgroup.asset.distribution.service.httpclient.IHttpService
;
import
com.quantgroup.asset.distribution.service.httpclient.IHttpService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtend
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAssetAttributeExtendRepository
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAssetRepository
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
...
@@ -36,6 +42,10 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
...
@@ -36,6 +42,10 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
@Autowired
@Autowired
private
IHttpService
httpService
;
private
IHttpService
httpService
;
@Autowired
private
IAssetRepository
assetRepository
;
@Autowired
private
IAssetAttributeExtendRepository
assetAttributeExtendRepository
;
@Value
(
"${rule.engine.url}"
)
@Value
(
"${rule.engine.url}"
)
private
String
ruleEngineURL
;
private
String
ruleEngineURL
;
...
@@ -46,20 +56,16 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
...
@@ -46,20 +56,16 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
@Override
@Override
public
Map
<
String
,
Object
>
getAllAssetAttributeValue
(
List
<
AssetAttributeExtendConfig
>
assetAttributeExtendConfigList
,
AssetForm
assetForm
)
{
public
Map
<
String
,
Object
>
getAllAssetAttributeValue
(
List
<
AssetAttributeExtendConfig
>
assetAttributeExtendConfigList
,
AssetForm
assetForm
)
{
Map
<
String
,
Object
>
data
=
new
HashMap
<>();
Map
<
String
,
Object
>
data
=
new
HashMap
<>();
// 决策特征Set
data
.
put
(
AssetAttributeConstants
.
AUDIT_RESULT
,
assetForm
.
getAuditResult
());
// 决策特征Key
Set
<
String
>
decKeys
=
new
HashSet
<>();
Set
<
String
>
decKeys
=
new
HashSet
<>();
// 默认增加一个用户类型
decKeys
.
add
(
AssetAttributeConstants
.
USER_LOAN_TYPE
);
decKeys
.
add
(
"user_loan_type_latest"
);
if
(
assetAttributeExtendConfigList
!=
null
&&
assetAttributeExtendConfigList
.
size
()
>
0
)
{
if
(
assetAttributeExtendConfigList
!=
null
&&
assetAttributeExtendConfigList
.
size
()
>
0
)
{
for
(
AssetAttributeExtendConfig
config
:
assetAttributeExtendConfigList
)
{
for
(
AssetAttributeExtendConfig
config
:
assetAttributeExtendConfigList
)
{
if
(
config
.
getAssetAttributeType
()
==
1
)
{
if
(
config
.
getAssetAttributeType
()
==
1
)
{
decKeys
.
add
(
config
.
getAssetAttributeCode
());
}
// 模型分
decKeys
.
add
(
config
.
getAssetAttributeCode
());
}
}
}
}
}
// 请求决策特征
// 去请求决策特征
Map
<
String
,
Object
>
decAttributeValue
=
getDecAttributeValue
(
decKeys
,
assetForm
);
Map
<
String
,
Object
>
decAttributeValue
=
getDecAttributeValue
(
decKeys
,
assetForm
);
data
.
putAll
(
decAttributeValue
);
data
.
putAll
(
decAttributeValue
);
return
data
;
return
data
;
...
@@ -71,18 +77,46 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
...
@@ -71,18 +77,46 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
* @return
* @return
*/
*/
public
Map
<
String
,
Object
>
getDecAttributeValue
(
Set
<
String
>
decKeys
,
AssetForm
assetForm
)
{
public
Map
<
String
,
Object
>
getDecAttributeValue
(
Set
<
String
>
decKeys
,
AssetForm
assetForm
)
{
if
(
CollectionUtils
.
isEmpty
(
decKeys
))
{
return
MapUtils
.
EMPTY_MAP
;
}
// TODO
String
result
=
httpService
.
post
(
ruleEngineURL
+
"/feature/get"
,
new
HashMap
<
String
,
String
>(){{
// if (CollectionUtils.isEmpty(decKeys)) { return MapUtils.EMPTY_MAP; }
put
(
"uuid"
,
assetForm
.
getUuid
());
// String result = httpService.post(ruleEngineURL + "/feature/get", new HashMap<String, String>(){{
put
(
"bizChannel"
,
assetForm
.
getBizChannel
());
// put("uuid", assetForm.getUuid());
put
(
"bizNo"
,
assetForm
.
getBizNo
());
// put("bizChannel", assetForm.getBizChannel());
put
(
"bizType"
,
assetForm
.
getBizType
());
// put("bizNo", assetForm.getBizNo());
put
(
"keys"
,
StringUtils
.
join
(
decKeys
,
","
));
// put("bizType", assetForm.getBizType());
}});
// put("keys", StringUtils.join(decKeys, ","));
JSONObject
resultJSON
=
null
;
// }});
QGPreconditions
.
checkArgument
(
StringUtils
.
isNotEmpty
(
result
)
&&
(
resultJSON
=
JSON
.
parseObject
(
result
)).
getInteger
(
"code"
)
==
0
,
QGExceptionType
.
GET_DEC_ATTRIBUTE_VALUE_ERROR
,
assetForm
.
getUuid
(),
JSON
.
toJSONString
(
decKeys
));
// JSONObject resultJSON = null;
Map
<
String
,
Object
>
data
=
resultJSON
.
getJSONObject
(
"body"
);
// QGPreconditions.checkArgument(StringUtils.isNotEmpty(result) && (resultJSON = JSON.parseObject(result)).getInteger("code") == 0, QGExceptionType.GET_DEC_ATTRIBUTE_VALUE_ERROR, assetForm.getUuid(), JSON.toJSONString(decKeys));
log
.
info
(
"决策特征属性获取完成, uuid : {}, bizChannel : {}, bizNo : {}, bizType : {}, data : {}"
,
assetForm
.
getUuid
(),
assetForm
.
getBizChannel
(),
assetForm
.
getBizNo
(),
assetForm
.
getBizType
(),
JSON
.
toJSONString
(
data
));
// Map<String, Object > data = resultJSON.getJSONObject("body");
// log.info("决策特征属性获取完成, uuid : {}, bizChannel : {}, bizNo : {}, bizType : {}, data : {}", assetForm.getUuid(), assetForm.getBizChannel(), assetForm.getBizNo(), assetForm.getBizType(), JSON.toJSONString(data));
Map
<
String
,
Object
>
data
=
new
HashMap
<>();
data
.
put
(
AssetAttributeConstants
.
USER_LOAN_TYPE
,
1
);
return
data
;
return
data
;
}
}
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Override
public
void
saveAssetAttrubite
(
Asset
asset
,
List
<
AssetAttributeExtendConfig
>
assetAttributeExtendConfigList
,
Map
<
String
,
Object
>
data
)
{
// 用户类型特殊处理
QGPreconditions
.
checkArgument
(
data
.
get
(
AssetAttributeConstants
.
USER_LOAN_TYPE
)
!=
null
,
QGExceptionType
.
ASSET_ATTRIBUTE_IS_EMPTY
,
AssetAttributeConstants
.
USER_LOAN_TYPE
);
asset
.
setUserLoanType
((
Integer
)
data
.
get
(
AssetAttributeConstants
.
USER_LOAN_TYPE
));
data
.
put
(
"user_loan_type"
,
data
.
get
(
AssetAttributeConstants
.
USER_LOAN_TYPE
));
assetRepository
.
save
(
asset
);
if
(
assetAttributeExtendConfigList
!=
null
&&
assetAttributeExtendConfigList
.
size
()
>
0
)
{
for
(
AssetAttributeExtendConfig
config
:
assetAttributeExtendConfigList
)
{
QGPreconditions
.
checkArgument
(
data
.
get
(
config
.
getAssetAttributeCode
())
!=
null
,
QGExceptionType
.
ASSET_ATTRIBUTE_IS_EMPTY
,
config
.
getAssetAttributeCode
());
AssetAttributeExtend
attributeExtend
=
new
AssetAttributeExtend
();
attributeExtend
.
setAssetNo
(
asset
.
getAssetNo
());
attributeExtend
.
setAssetAttributeName
(
config
.
getAssetAttributeName
());
attributeExtend
.
setAssetAttributeCode
(
config
.
getAssetAttributeCode
());
attributeExtend
.
setAssetAttributeType
(
config
.
getAssetAttributeType
());
attributeExtend
.
setAssetAttributeValue
(
String
.
valueOf
(
data
.
get
(
config
.
getAssetAttributeCode
())));
attributeExtend
.
setEnable
(
true
);
assetAttributeExtendRepository
.
save
(
attributeExtend
);
}
}
}
}
}
src/main/java/com/quantgroup/asset/distribution/service/asset/impl/AssetServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
asset
.
impl
;
import
java.math.BigDecimal
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.quantgroup.asset.distribution.constant.DistributeLogoConstants
;
import
com.quantgroup.asset.distribution.exception.QGException
;
import
com.quantgroup.asset.distribution.exception.QGExceptionType
;
import
com.quantgroup.asset.distribution.exception.QGPreconditions
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.service.alarm.IAlarmService
;
import
com.quantgroup.asset.distribution.service.asset.IAssetAttributeExtendConfigService
;
import
com.quantgroup.asset.distribution.service.asset.IAssetAttributeService
;
import
com.quantgroup.asset.distribution.service.asset.IAssetService
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService
;
import
com.quantgroup.asset.distribution.service.distribute.IDistributeFailLogService
;
import
com.quantgroup.asset.distribution.service.httpclient.IHttpService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAssetAttributeExtendConfigRepository
;
import
com.quantgroup.asset.distribution.util.UUIDUtil
;
import
lombok.extern.slf4j.Slf4j
;
/**
* 资产Service
* @author liwenbin
*
*/
@Slf4j
@Service
public
class
AssetServiceImpl
implements
IAssetService
{
@Autowired
private
IAssetAttributeExtendConfigService
assetAttributeExtendConfigService
;
@Autowired
private
IAssetAttributeService
assetAttributeService
;
@Autowired
private
IAssetDistributeService
assetDistributeService
;
@Autowired
private
IAlarmService
alarmService
;
@Autowired
private
IDistributeFailLogService
distributeFailLogService
;
@Async
@Override
public
void
assetsIn
(
AssetForm
assetForm
)
{
try
{
Asset
asset
=
assetForm
.
transToAsset
();
// 获取所有资产扩展属性配置
List
<
AssetAttributeExtendConfig
>
assetAttributeExtendConfigList
=
assetAttributeExtendConfigService
.
getAllExtendConfig
();
// 获取所有资产扩展属性值
Map
<
String
,
Object
>
data
=
assetAttributeService
.
getAllAssetAttributeValue
(
assetAttributeExtendConfigList
,
assetForm
);
// 资产入库
assetAttributeService
.
saveAssetAttrubite
(
asset
,
assetAttributeExtendConfigList
,
data
);
// 资产分发
assetDistributeService
.
distribute
(
assetForm
,
asset
,
data
,
DistributeLogoConstants
.
FIRST
);
}
catch
(
QGException
qe
)
{
log
.
error
(
"资产入库分发出现错误 : {}, uuid : {}, bizChannel : {}, bizType : {}, bizNo : {}, assetNo : {} "
,
qe
.
qgExceptionType
.
code
+
"->"
+
qe
.
detail
,
assetForm
.
getUuid
(),
assetForm
.
getBizChannel
(),
assetForm
.
getBizType
(),
assetForm
.
getBizNo
(),
assetForm
.
getAssetNo
());
distributeFailLogService
.
saveDistributeFailLog
(
assetForm
,
qe
.
qgExceptionType
.
code
+
"->"
+
qe
.
detail
);
alarmService
.
dingtalkAlarm
(
"Warn"
,
"资产入库分发出现错误"
,
"bizChannel : "
+
assetForm
.
getBizChannel
()
+
" , bizType : "
+
assetForm
.
getBizType
()
+
" , bizNo : "
+
assetForm
.
getBizNo
()
+
" , assetNo : "
+
assetForm
.
getAssetNo
()
+
" , uuid : "
+
assetForm
.
getUuid
()
+
" , 错误信息 : "
+
qe
.
qgExceptionType
.
code
+
"->"
+
qe
.
detail
);
}
catch
(
Exception
ex
)
{
log
.
error
(
"资产入库分发出现异常, uuid : {}, bizChannel : {}, bizType : {}, bizNo : {}, assetNo : {} "
,
assetForm
.
getUuid
(),
assetForm
.
getBizChannel
(),
assetForm
.
getBizType
(),
assetForm
.
getBizNo
(),
assetForm
.
getAssetNo
(),
ex
);
distributeFailLogService
.
saveDistributeFailLog
(
assetForm
,
"未知异常."
);
alarmService
.
dingtalkAlarm
(
"Warn"
,
"资产入库分发出现异常"
,
"bizChannel : "
+
assetForm
.
getBizChannel
()
+
" , bizType : "
+
assetForm
.
getBizType
()
+
" , bizNo : "
+
assetForm
.
getBizNo
()
+
" , assetNo : "
+
assetForm
.
getAssetNo
()
+
" , uuid : "
+
assetForm
.
getUuid
()
+
" , 错误信息 : 未知错误."
);
}
}
@Override
public
boolean
checkAssetForm
(
AssetForm
assetForm
)
{
// auditResult和deadLine必填
if
(
StringUtils
.
isEmpty
(
assetForm
.
getAuditResult
())
||
StringUtils
.
isEmpty
(
assetForm
.
getDeadLine
()))
{
return
false
;
}
if
(
"true"
.
equals
(
assetForm
.
getAuditResult
()))
{
if
(
StringUtils
.
isEmpty
(
assetForm
.
getFinanceProducts
())
||
StringUtils
.
isEmpty
(
assetForm
.
getAmount
()))
{
// auditResult为true,金融产品集和amount不能为空
return
false
;
}
BigDecimal
amount
=
new
BigDecimal
(
assetForm
.
getAmount
());
BigDecimal
floor
=
null
;
JSONArray
array
=
JSON
.
parseArray
(
assetForm
.
getFinanceProducts
());
for
(
int
i
=
0
,
len
=
array
.
size
();
i
<
len
;
++
i
)
{
JSONObject
data
=
array
.
getJSONObject
(
i
);
BigDecimal
min
=
new
BigDecimal
(
data
.
getString
(
"min"
));
BigDecimal
max
=
new
BigDecimal
(
data
.
getString
(
"max"
));
BigDecimal
cha
=
max
.
subtract
(
min
);
// 0 <= max - min <= 1
if
(!(
cha
.
compareTo
(
BigDecimal
.
ZERO
)
>
-
1
&&
cha
.
compareTo
(
BigDecimal
.
ONE
)
<
1
))
{
return
false
;
}
if
(
floor
==
null
||
min
.
compareTo
(
floor
)
<
0
)
{
floor
=
min
;
}
}
// amount >= floor
if
(
amount
.
compareTo
(
floor
)
<
1
)
{
return
false
;
}
}
return
true
;
}
public
static
void
main
(
String
[]
args
)
{
BigDecimal
min
=
new
BigDecimal
(
"98"
);
BigDecimal
max
=
new
BigDecimal
(
"100"
);
BigDecimal
cha
=
max
.
subtract
(
min
);
if
(
cha
.
compareTo
(
BigDecimal
.
ZERO
)
>
-
1
&&
cha
.
compareTo
(
BigDecimal
.
ONE
)
<
1
)
{
System
.
out
.
println
(
true
);
}
else
{
System
.
out
.
println
(
false
);
}
}
}
src/main/java/com/quantgroup/asset/distribution/service/IAuthorityService.java
→
src/main/java/com/quantgroup/asset/distribution/service/
authority/
IAuthorityService.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
authority
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
...
...
src/main/java/com/quantgroup/asset/distribution/service/impl/AuthorityServiceImpl.java
→
src/main/java/com/quantgroup/asset/distribution/service/
authority/
impl/AuthorityServiceImpl.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
impl
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
authority
.
impl
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cache.annotation.CacheEvict
;
import
org.springframework.cache.annotation.CacheEvict
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.data.redis.cache.RedisCache
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
com.quantgroup.asset.distribution.service.IAuthorityService
;
import
com.quantgroup.asset.distribution.service.
authority.
IAuthorityService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAuthorityRepository
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAuthorityRepository
;
...
@@ -25,13 +24,13 @@ public class AuthorityServiceImpl implements IAuthorityService{
...
@@ -25,13 +24,13 @@ public class AuthorityServiceImpl implements IAuthorityService{
private
IAuthorityRepository
authorityRepository
;
private
IAuthorityRepository
authorityRepository
;
@Override
@Override
@Cacheable
(
value
=
"cacheManager"
,
key
=
"#authKey+'_'+#authPass+'_1021ASSET'"
)
@Cacheable
(
value
=
"cacheManager"
,
key
=
"#authKey+'_'+#authPass+'_1021ASSET
_AUTHORITY
'"
)
public
AuthorityConfig
findByAuthKeyAndAuthPass
(
String
authKey
,
String
authPass
)
{
public
AuthorityConfig
findByAuthKeyAndAuthPass
(
String
authKey
,
String
authPass
)
{
return
authorityRepository
.
findByAuthKeyAndAuthPassAndEnableIsTrue
(
authKey
,
authPass
);
return
authorityRepository
.
findByAuthKeyAndAuthPassAndEnableIsTrue
(
authKey
,
authPass
);
}
}
@Override
@Override
@CacheEvict
(
value
=
"cacheManager"
,
key
=
"#authKey+'_'+#authPass+'_1021ASSET'"
)
@CacheEvict
(
value
=
"cacheManager"
,
key
=
"#authKey+'_'+#authPass+'_1021ASSET
_AUTHORITY
'"
)
public
void
clearCacheByAuthKeyAndAuthPass
(
String
authKey
,
String
authPass
)
{
public
void
clearCacheByAuthKeyAndAuthPass
(
String
authKey
,
String
authPass
)
{
log
.
info
(
"权限配置清楚缓存成功, authKey = {}, authPass = {}"
,
authKey
,
authPass
);
log
.
info
(
"权限配置清楚缓存成功, authKey = {}, authPass = {}"
,
authKey
,
authPass
);
}
}
...
...
src/main/java/com/quantgroup/asset/distribution/service/distribute/IAssetDistributeRecordService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
;
import
java.util.List
;
import
com.quantgroup.asset.distribution.model.entity.DistributeRecord
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRecord
;
/**
* 资产分发记录Service
* @author liwenbin
*
*/
public
interface
IAssetDistributeRecordService
{
/**
* 保存记录
* @param asset
* @param distributeRecord
* @param distributeStatus
*/
public
void
saveDistributeRecord
(
Asset
asset
,
DistributeRecord
distributeRecord
,
Boolean
distributeStatus
,
int
ruleType
);
/**
* 获取资产分发记录
* @param assetNo
* @return
*/
public
List
<
AssetDistributeRecord
>
getDistributeRecord
(
String
assetNo
);
}
src/main/java/com/quantgroup/asset/distribution/service/distribute/IAssetDistributeRuleConfigService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
;
import
java.util.List
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRuleConfig
;
/**
* 资产分发规则配置Service
* @author liwenbin
*
*/
public
interface
IAssetDistributeRuleConfigService
{
public
List
<
AssetDistributeRuleConfig
>
getAllRuleConfigOrderByPriorityAsc
();
public
void
clearRuleConfigCache
();
}
src/main/java/com/quantgroup/asset/distribution/service/distribute/IAssetDistributeService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
;
import
java.util.Map
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
/**
* 资产分发Service
* @author liwenbin
*
*/
public
interface
IAssetDistributeService
{
/**
* 资产开始分发
* @param assetForm
* @param asset
* @param startIndex 开始分发节点
* @param distributeLogo 1:初次分发或异常重试, 2:分发失败重新分发(预留)
*/
public
void
distribute
(
AssetForm
assetForm
,
Asset
asset
,
Map
<
String
,
Object
>
data
,
int
distributeLogo
);
}
src/main/java/com/quantgroup/asset/distribution/service/distribute/IDistributeFailLogService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
/**
* 分发失败日志处理Service
* @author liwenbin
*
*/
public
interface
IDistributeFailLogService
{
/**
* 保存失败订单
* @param assetForm
* @param failReason
*/
public
void
saveDistributeFailLog
(
AssetForm
assetForm
,
String
failReason
);
}
src/main/java/com/quantgroup/asset/distribution/service/distribute/impl/AssetDistributeRecordServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
.
impl
;
import
java.util.List
;
import
java.util.Set
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
com.alibaba.fastjson.JSON
;
import
com.quantgroup.asset.distribution.constant.StatusConstants
;
import
com.quantgroup.asset.distribution.model.entity.DistributeRecord
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRecordService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRecord
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAssetDistributeRecordRepository
;
import
com.quantgroup.asset.distribution.service.redis.IRedisService
;
import
lombok.extern.slf4j.Slf4j
;
/**
* 资产分发日志记录表
* @author liwenbin
*
*/
@Slf4j
@Service
public
class
AssetDistributeRecordServiceImpl
implements
IAssetDistributeRecordService
{
@Autowired
private
IAssetDistributeRecordRepository
assetDistributeRecordRepository
;
@Autowired
private
IRedisService
<
Integer
>
redisService
;
@Override
public
void
saveDistributeRecord
(
Asset
asset
,
DistributeRecord
distributeRecord
,
Boolean
distributeStatus
,
int
ruleType
)
{
try
{
AssetDistributeRecord
assetDistributeRecord
=
new
AssetDistributeRecord
();
assetDistributeRecord
.
setAssetNo
(
asset
.
getAssetNo
());
assetDistributeRecord
.
setUuid
(
asset
.
getUuid
());
assetDistributeRecord
.
setUserLoanType
(
asset
.
getUserLoanType
());
assetDistributeRecord
.
setBizChannel
(
asset
.
getBizChannel
());
assetDistributeRecord
.
setFinanceProductType
(
asset
.
getFinanceProductType
());
assetDistributeRecord
.
setBizNo
(
asset
.
getBizNo
());
assetDistributeRecord
.
setAssetDistributeTravel
(
JSON
.
toJSONString
(
distributeRecord
));
assetDistributeRecord
.
setAssetDistributeTarget
(
ruleType
);
assetDistributeRecord
.
setAssetDistributeStatus
(
distributeStatus
==
true
?
StatusConstants
.
SUCCESS
:
StatusConstants
.
FAIL
);
assetDistributeRecord
.
setEnable
(
true
);
assetDistributeRecordRepository
.
save
(
assetDistributeRecord
);
// 完成一次分发,清除分发记录
distributeRecord
.
clearRecords
();
}
catch
(
Exception
e
)
{
log
.
error
(
"用户记录分发日志异常, uuid : {}"
,
asset
.
getUuid
(),
e
);
}
}
@Override
public
List
<
AssetDistributeRecord
>
getDistributeRecord
(
String
assetNo
)
{
return
assetDistributeRecordRepository
.
findByAssetNo
(
assetNo
);
}
}
src/main/java/com/quantgroup/asset/distribution/service/distribute/impl/AssetDistributeRuleConfigServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
.
impl
;
import
java.util.List
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cache.annotation.CacheEvict
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.stereotype.Service
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRuleConfigService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRuleConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAssetDistributeRuleConfigRepository
;
/**
* 资产分发规则配置Service
* @author liwenbin
*
*/
@Service
public
class
AssetDistributeRuleConfigServiceImpl
implements
IAssetDistributeRuleConfigService
{
@Autowired
private
IAssetDistributeRuleConfigRepository
assetDistributeRuleConfigRepository
;
@Override
@Cacheable
(
value
=
"cacheManager"
,
key
=
"'ASSET_2028D_ALL_RULE_CONFIG'"
)
public
List
<
AssetDistributeRuleConfig
>
getAllRuleConfigOrderByPriorityAsc
()
{
return
assetDistributeRuleConfigRepository
.
findByEnableIsTrueOrderByAssetDistributeRulePriorityAsc
();
}
@Override
@CacheEvict
(
value
=
"cacheManager"
,
key
=
"'ASSET_2028D_ALL_RULE_CONFIG'"
)
public
void
clearRuleConfigCache
()
{
}
}
src/main/java/com/quantgroup/asset/distribution/service/distribute/impl/AssetDistributeServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
.
impl
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.google.common.collect.Sets
;
import
com.quantgroup.asset.distribution.constant.DistributeConstants
;
import
com.quantgroup.asset.distribution.constant.RedisKeyConstants
;
import
com.quantgroup.asset.distribution.exception.QGException
;
import
com.quantgroup.asset.distribution.exception.QGExceptionType
;
import
com.quantgroup.asset.distribution.model.entity.DistributeRecord
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRecordService
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRuleConfigService
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService
;
import
com.quantgroup.asset.distribution.service.funding.IAidFundRouteService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRecord
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRuleConfig
;
import
com.quantgroup.asset.distribution.service.notify.INotifyService
;
import
com.quantgroup.asset.distribution.service.redis.IRedisService
;
import
com.quantgroup.asset.distribution.service.rule.IRuleService
;
/**
* 资产分发Service
* @author liwenbin
*
*/
@Service
public
class
AssetDistributeServiceImpl
implements
IAssetDistributeService
{
/**
* 分发总开关
*/
@Value
(
"${is.distribute}"
)
private
Boolean
isDistribute
;
@Autowired
private
IAssetDistributeRuleConfigService
assetDistributeRuleConfigService
;
@Autowired
private
IRedisService
<
Integer
>
redisService
;
@Autowired
private
IRuleService
ruleService
;
@Autowired
private
IAidFundRouteService
aidFundRouteService
;
@Autowired
private
INotifyService
notifyService
;
@Autowired
private
IAssetDistributeRecordService
assetDistributeRecordService
;
/**
* 分发
*/
@Override
public
void
distribute
(
AssetForm
assetForm
,
Asset
asset
,
Map
<
String
,
Object
>
data
,
int
distributeLogo
)
{
if
(
isDistribute
)
{
List
<
AssetDistributeRuleConfig
>
assetDistributeRuleConfigList
=
assetDistributeRuleConfigService
.
getAllRuleConfigOrderByPriorityAsc
();
// 检查规则配置
checkDistributeRuleConfig
(
assetDistributeRuleConfigList
);
// 获取该资产所有已经尝试分发过的类型
Set
<
Integer
>
hasDistributedTypeSet
=
getAllDistributeRecordType
(
asset
.
getAssetNo
(),
distributeLogo
);
boolean
success
=
false
;
DistributeRecord
record
=
new
DistributeRecord
(
data
);
for
(
AssetDistributeRuleConfig
ruleConfig
:
assetDistributeRuleConfigList
)
{
Integer
ruleType
=
ruleConfig
.
getAssetDistributeRuleType
();
// 如果配置被关闭或者该类型被分发过,就默认往下走,主要避免priority调换顺序的情况
if
(
ruleConfig
.
getAssetDistributeRuleSwitch
()
==
0
||
hasDistributedTypeSet
.
contains
(
ruleType
))
{
continue
;
}
String
el
=
ruleConfig
.
getAssetDistributeRuleEl
();
boolean
valid
=
ruleService
.
valid
(
el
,
data
);
record
.
addRecords
(
ruleConfig
.
getId
(),
el
,
ruleType
,
ruleConfig
.
getAssetDistributeRuleName
(),
valid
);
// 保存节点尝试记录
saveAssetAttemptDistributeNode
(
asset
.
getAssetNo
(),
ruleType
);
if
(
valid
)
{
boolean
distributeStatus
=
beginDistribute
(
assetForm
,
asset
,
ruleType
);
assetDistributeRecordService
.
saveDistributeRecord
(
asset
,
record
,
distributeStatus
,
ruleType
);
// 分发成功
if
(
distributeStatus
)
{
success
=
true
;
break
;
}
}
}
if
(!
success
)
{
// 如果一个分配节点都没找到,报错
throw
new
QGException
(
QGExceptionType
.
NO_DISTRIBUTE_NODE
,
asset
.
getUuid
(),
asset
.
getAssetNo
(),
JSON
.
toJSONString
(
record
));
}
}
else
{
notifyService
.
notifyFundServer
(
assetForm
);
}
}
/**
* 开始进行分发
* @param assetForm
* @param ruleType
* @return
*/
public
boolean
beginDistribute
(
AssetForm
assetForm
,
Asset
asset
,
int
ruleType
)
{
switch
(
ruleType
)
{
case
DistributeConstants
.
RuleType
.
FUND_ROUTE
:
notifyService
.
notifyFundServer
(
assetForm
);
return
true
;
case
DistributeConstants
.
RuleType
.
AID_FUND_ROUTE
:
GlobalResponse
response
=
aidFundRouteService
.
aidFundRoute
(
assetForm
,
asset
.
getUserLoanType
());
return
response
.
getCode
()
==
0
;
case
DistributeConstants
.
RuleType
.
DIVERSION
:
notifyService
.
notifyFundServer
(
assetForm
);
return
true
;
default
:
throw
new
QGException
(
QGExceptionType
.
UNKNOW_RULE_TYPE
,
ruleType
);
}
}
/**
* 分发配置检查
* @param assetDistributeRuleConfigList
*/
public
void
checkDistributeRuleConfig
(
List
<
AssetDistributeRuleConfig
>
assetDistributeRuleConfigList
)
{
int
prePriority
=
-
1
;
for
(
AssetDistributeRuleConfig
assetDistributeRuleConfig
:
assetDistributeRuleConfigList
)
{
if
(
assetDistributeRuleConfig
.
getAssetDistributeRulePriority
().
equals
(
prePriority
))
{
throw
new
QGException
(
QGExceptionType
.
DISTRIBUTE_RULE_CONFIG_PRIORITY_IS_NOT_UNIQUE
);
}
prePriority
=
assetDistributeRuleConfig
.
getAssetDistributeRulePriority
();
}
}
/**
* 获取该用户所有分发记录Type,如果用户初次分发或者异常重试返回空
* @param assetNo
* @return
*/
public
Set
<
Integer
>
getAllDistributeRecordType
(
String
assetNo
,
int
distributeLogo
)
{
Set
<
Integer
>
sets
=
new
HashSet
<>();
if
(
distributeLogo
==
1
)
{
// 用户初次分发或者异常重试直接返回空
return
sets
;
}
List
<
Integer
>
list
=
redisService
.
getList
(
RedisKeyConstants
.
DISTRIBUTE_FAIL_TYPE_RECORD
+
assetNo
);
if
(
list
==
null
||
list
.
size
()
==
0
)
{
// 如果缓存没有去查库,把库里执行过的都拿出来
List
<
AssetDistributeRecord
>
assetDistributeRecords
=
assetDistributeRecordService
.
getDistributeRecord
(
assetNo
);
if
(
assetDistributeRecords
==
null
||
assetDistributeRecords
.
size
()
==
0
)
{
return
sets
;
}
list
=
new
ArrayList
<>();
for
(
AssetDistributeRecord
assetDistributeRecord
:
assetDistributeRecords
)
{
JSONArray
array
=
JSON
.
parseObject
(
assetDistributeRecord
.
getAssetDistributeTravel
()).
getJSONArray
(
"records"
);
for
(
int
i
=
0
,
len
=
array
.
size
();
i
<
len
;
++
i
)
{
JSONObject
record
=
array
.
getJSONObject
(
i
);
list
.
add
(
record
.
getInteger
(
"type"
));
}
}
}
sets
.
addAll
(
list
);
return
sets
;
}
/**
* 保存资产尝试分发记录节点
*/
public
void
saveAssetAttemptDistributeNode
(
String
assetNo
,
Integer
ruleType
)
{
redisService
.
rightPushEx
(
RedisKeyConstants
.
DISTRIBUTE_FAIL_TYPE_RECORD
+
assetNo
,
ruleType
,
3
,
TimeUnit
.
DAYS
);
}
}
src/main/java/com/quantgroup/asset/distribution/service/distribute/impl/DistributeFailLogServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
distribute
.
impl
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
com.alibaba.fastjson.JSON
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.service.distribute.IDistributeFailLogService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.DistributeFailLog
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IDistributeFailLogRepository
;
import
lombok.extern.slf4j.Slf4j
;
@Slf4j
@Service
public
class
DistributeFailLogServiceImpl
implements
IDistributeFailLogService
{
@Autowired
private
IDistributeFailLogRepository
distributeFailLogRepository
;
@Async
@Override
public
void
saveDistributeFailLog
(
AssetForm
assetForm
,
String
failReason
)
{
try
{
DistributeFailLog
distributeFailLog
=
new
DistributeFailLog
();
distributeFailLog
.
setBizChannel
(
assetForm
.
getBizChannel
());
distributeFailLog
.
setAssetNo
(
assetForm
.
getAssetNo
());
distributeFailLog
.
setBizNo
(
assetForm
.
getBizNo
());
distributeFailLog
.
setBizType
(
Integer
.
parseInt
(
assetForm
.
getBizType
()));
distributeFailLog
.
setUuid
(
assetForm
.
getUuid
());
distributeFailLog
.
setContext
(
JSON
.
toJSONString
(
assetForm
));
distributeFailLog
.
setFailReason
(
failReason
);
distributeFailLog
.
setEnable
(
true
);
distributeFailLogRepository
.
save
(
distributeFailLog
);
}
catch
(
Exception
e
)
{
log
.
error
(
"资产分发失败订单保存异常, asset : {}"
,
JSON
.
toJSONString
(
assetForm
),
e
);
}
}
}
src/main/java/com/quantgroup/asset/distribution/service/impl/AssetServiceImpl.java
deleted
100644 → 0
View file @
bc98d9e1
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
impl
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
com.quantgroup.asset.distribution.exception.QGException
;
import
com.quantgroup.asset.distribution.exception.QGExceptionType
;
import
com.quantgroup.asset.distribution.exception.QGPreconditions
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.model.response.GlobalResponse
;
import
com.quantgroup.asset.distribution.service.IAssetService
;
import
com.quantgroup.asset.distribution.service.httpclient.IHttpService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.Asset
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAssetAttributeExtendConfigRepository
;
import
com.quantgroup.asset.distribution.util.UUIDUtil
;
/**
* 资产Service
* @author liwenbin
*
*/
@Service
public
class
AssetServiceImpl
implements
IAssetService
{
@Autowired
private
IAssetAttributeExtendConfigRepository
assetAttributeExtendConfigRepository
;
@Async
@Override
public
void
assetsIn
(
AssetForm
assetForm
)
{
// try {
// QGPreconditions.checkArgument("0".equals(assetForm.getCode()), QGExceptionType.ASSET_IN_CODE_ERROR, assetForm.getUuid(), assetForm.getBizNo(), assetForm.getCode());
// Asset asset = assetForm.transToAsset();
// // 获取所有资产扩展属性配置
// List<AssetAttributeExtendConfig> assetAttributeExtendConfigList = assetAttributeExtendConfigRepository.findByEnableIsTrue();
//
// return null;
// } catch (QGException qe) {
// log.error("风控审核出现错误:{},审核次数 : {} ,uuid : {} ,bizChannel:{},productId:{},bizNo : {},auditNo:{} ",
// qe.qgExceptionType.code + "->" + qe.detail, bizAuditForm.getRepeatCount(),
// bizAuditForm.getUuid(), bizAuditForm.getBizChannel(), bizAuditForm.getProductId(),
// bizAuditForm.getBizNo(), bizAuditForm.getAuditNo());
// // 审核失败放队列 来日继续审核
// iRedisService.rightPushEx("AUDIT.ERROR.USER.9981_01",
// bizAuditForm.setRepeatCount(bizAuditForm.getRepeatCount() + 1)
// .setFailReason(qe.qgExceptionType.code + "->" + qe.detail)
// .setSpaceTime(System.currentTimeMillis()),
// 1, TimeUnit.DAYS);
// // 报警机制
// if (qe.qgExceptionType.code != 2007 || bizAuditForm.getRepeatCount() > 1) {//规则数据为空 一次不报警 因为太多了
// iMonitorAlarmService.alarm("风控审核出现错误",
// "审核次数 : " + bizAuditForm.getRepeatCount() + " ,bizChannel : " + bizAuditForm.getBizChannel()
// + " , productId : " + bizAuditForm.getProductId() + " , bizNo : "
// + bizAuditForm.getBizNo() + " , uuid : " + bizAuditForm.getUuid() + " , 错误信息 : "
// + qe.qgExceptionType.code + "->" + qe.detail,
// "Warn");
// }
// return;
// } catch (Exception ex) {
// log.error("风控审核出现异常,审核次数 : {} ,uuid: {} ,bizChannel : {} ,productId:{},bizNo : {},auditNo:{} ",
// bizAuditForm.getRepeatCount(), bizAuditForm.getUuid(), bizAuditForm.getBizChannel(),
// bizAuditForm.getProductId(), bizAuditForm.getBizNo(), bizAuditForm.getAuditNo(), ex);
// // 审核失败放队列 来日继续审核
// iRedisService.rightPushEx("AUDIT.ERROR.USER.9981_01",
// bizAuditForm.setRepeatCount(bizAuditForm.getRepeatCount() + 1).setFailReason("未知异常")
// .setSpaceTime(System.currentTimeMillis()),
// 1, TimeUnit.DAYS);
// // 报警机制
// iMonitorAlarmService.alarm("风控审核出现异常",
// "审核次数 : " + bizAuditForm.getRepeatCount() + " , bizChannel : " + bizAuditForm.getBizChannel()
// + " , productId : " + bizAuditForm.getProductId() + " , bizNo : "
// + bizAuditForm.getBizNo() + " , uuid : " + bizAuditForm.getUuid() + " , 错误信息 : 未知错误",
// "Warn");
// return;
// }
}
@Override
public
GlobalResponse
checkAssetForm
(
AssetForm
assetForm
)
{
return
null
;
}
}
src/main/java/com/quantgroup/asset/distribution/service/jpa/entity/Asset.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
import
java.io.Serializable
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
javax.persistence.Column
;
import
javax.persistence.Column
;
...
@@ -23,8 +24,13 @@ import lombok.Setter;
...
@@ -23,8 +24,13 @@ import lombok.Setter;
@Table
(
name
=
"asset"
)
@Table
(
name
=
"asset"
)
@Entity
@Entity
@Data
@Data
public
class
Asset
{
public
class
Asset
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
@Id
@Id
@Column
(
name
=
"id"
)
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
...
...
src/main/java/com/quantgroup/asset/distribution/service/jpa/entity/AssetAttributeExtend.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
import
java.io.Serializable
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
javax.persistence.Column
;
import
javax.persistence.Column
;
...
@@ -21,8 +22,13 @@ import lombok.Data;
...
@@ -21,8 +22,13 @@ import lombok.Data;
@Table
(
name
=
"asset_atrribute_extend"
)
@Table
(
name
=
"asset_atrribute_extend"
)
@Entity
@Entity
@Data
@Data
public
class
AssetAttributeExtend
{
public
class
AssetAttributeExtend
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
@Id
@Id
@Column
(
name
=
"id"
)
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
...
...
src/main/java/com/quantgroup/asset/distribution/service/jpa/entity/AssetAttributeExtendConfig.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
import
java.io.Serializable
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
javax.persistence.Column
;
import
javax.persistence.Column
;
...
@@ -22,12 +23,17 @@ import lombok.Data;
...
@@ -22,12 +23,17 @@ import lombok.Data;
@Table
(
name
=
"asset_atrribute_extend_config"
)
@Table
(
name
=
"asset_atrribute_extend_config"
)
@Entity
@Entity
@Data
@Data
public
class
AssetAttributeExtendConfig
{
public
class
AssetAttributeExtendConfig
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
@Id
@Id
@Column
(
name
=
"id"
)
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Integer
id
;
private
Long
id
;
@Column
(
name
=
"asset_attribute_name"
)
@Column
(
name
=
"asset_attribute_name"
)
private
String
assetAttributeName
;
private
String
assetAttributeName
;
...
...
src/main/java/com/quantgroup/asset/distribution/service/jpa/entity/AssetDistributeRecord.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
import
java.io.Serializable
;
import
java.sql.Timestamp
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.GenerationType
;
import
javax.persistence.Id
;
import
javax.persistence.PrePersist
;
import
javax.persistence.PreUpdate
;
import
javax.persistence.Table
;
import
lombok.Data
;
/**
* 资产分发记录表
* @author liwenbin
*
*/
@Table
(
name
=
"asset_distribute_record"
)
@Entity
@Data
public
class
AssetDistributeRecord
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
@Id
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
name
=
"asset_no"
)
private
String
assetNo
;
@Column
(
name
=
"uuid"
)
private
String
uuid
;
@Column
(
name
=
"user_loan_type"
)
private
Integer
userLoanType
;
@Column
(
name
=
"biz_channel"
)
private
String
bizChannel
;
@Column
(
name
=
"finance_product_type"
)
private
Integer
financeProductType
;
@Column
(
name
=
"biz_no"
)
private
String
bizNo
;
@Column
(
name
=
"asset_distribute_travel"
)
private
String
assetDistributeTravel
;
@Column
(
name
=
"asset_distribute_target"
)
private
Integer
assetDistributeTarget
;
@Column
(
name
=
"asset_distribute_status"
)
private
Integer
assetDistributeStatus
;
@Column
(
name
=
"enable"
)
private
Boolean
enable
;
@Column
(
name
=
"created_at"
)
private
Timestamp
createdAt
;
@Column
(
name
=
"updated_at"
)
private
Timestamp
updatedAt
;
@PrePersist
public
void
prePersist
()
{
Timestamp
timestamp
=
new
Timestamp
(
System
.
currentTimeMillis
());
createdAt
=
timestamp
;
updatedAt
=
timestamp
;
}
@PreUpdate
public
void
preUpdate
()
{
updatedAt
=
new
Timestamp
(
System
.
currentTimeMillis
());
}
}
src/main/java/com/quantgroup/asset/distribution/service/jpa/entity/AssetDistributeRuleConfig.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
import
java.io.Serializable
;
import
java.sql.Timestamp
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.GenerationType
;
import
javax.persistence.Id
;
import
javax.persistence.PrePersist
;
import
javax.persistence.PreUpdate
;
import
javax.persistence.Table
;
import
lombok.Data
;
/**
* 资产分发规则配置表
* @author liwenbin
*
*/
@Table
(
name
=
"asset_distribute_rule_config"
)
@Entity
@Data
public
class
AssetDistributeRuleConfig
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
@Id
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
name
=
"asset_distribute_rule_no"
)
private
String
assetDistributeRuleNo
;
@Column
(
name
=
"asset_distribute_rule_name"
)
private
String
assetDistributeRuleName
;
@Column
(
name
=
"asset_distribute_rule_type"
)
private
Integer
assetDistributeRuleType
;
@Column
(
name
=
"asset_distribute_rule_el"
)
private
String
assetDistributeRuleEl
;
@Column
(
name
=
"asset_distribute_rule_priority"
)
private
Integer
assetDistributeRulePriority
;
@Column
(
name
=
"asset_distribute_rule_switch"
)
private
Integer
assetDistributeRuleSwitch
;
@Column
(
name
=
"enable"
)
private
Boolean
enable
;
@Column
(
name
=
"created_by"
)
private
String
createdBy
;
@Column
(
name
=
"updated_by"
)
private
String
updatedBy
;
@Column
(
name
=
"created_at"
)
private
Timestamp
createdAt
;
@Column
(
name
=
"updated_at"
)
private
Timestamp
updatedAt
;
@PrePersist
public
void
prePersist
()
{
Timestamp
timestamp
=
new
Timestamp
(
System
.
currentTimeMillis
());
createdAt
=
timestamp
;
updatedAt
=
timestamp
;
}
@PreUpdate
public
void
preUpdate
()
{
updatedAt
=
new
Timestamp
(
System
.
currentTimeMillis
());
}
}
src/main/java/com/quantgroup/asset/distribution/service/jpa/entity/AuthorityConfig.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
import
java.io.Serializable
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
javax.persistence.Column
;
import
javax.persistence.Column
;
...
@@ -21,12 +22,17 @@ import lombok.Data;
...
@@ -21,12 +22,17 @@ import lombok.Data;
@Table
(
name
=
"authority_config"
)
@Table
(
name
=
"authority_config"
)
@Entity
@Entity
@Data
@Data
public
class
AuthorityConfig
{
public
class
AuthorityConfig
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
@Id
@Id
@Column
(
name
=
"id"
)
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Integer
id
;
private
Long
id
;
@Column
(
name
=
"auth_key"
)
@Column
(
name
=
"auth_key"
)
private
String
authKey
;
private
String
authKey
;
...
...
src/main/java/com/quantgroup/asset/distribution/service/jpa/entity/DistributeFailLog.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
entity
;
import
java.io.Serializable
;
import
java.sql.Timestamp
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.GenerationType
;
import
javax.persistence.Id
;
import
javax.persistence.PrePersist
;
import
javax.persistence.PreUpdate
;
import
javax.persistence.Table
;
import
lombok.Data
;
/**
* 分发失败日志表
* @author liwenbin
*
*/
@Table
(
name
=
"distribute_fail_log"
)
@Entity
@Data
public
class
DistributeFailLog
implements
Serializable
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
@Id
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
private
Long
id
;
@Column
(
name
=
"biz_channel"
)
private
String
bizChannel
;
@Column
(
name
=
"asset_no"
)
private
String
assetNo
;
@Column
(
name
=
"biz_no"
)
private
String
bizNo
;
@Column
(
name
=
"biz_type"
)
private
Integer
bizType
;
@Column
(
name
=
"uuid"
)
private
String
uuid
;
@Column
(
name
=
"context"
)
private
String
context
;
@Column
(
name
=
"fail_reason"
)
private
String
failReason
;
@Column
(
name
=
"enable"
)
private
Boolean
enable
;
@Column
(
name
=
"created_at"
)
private
Timestamp
createdAt
;
@Column
(
name
=
"updated_at"
)
private
Timestamp
updatedAt
;
@PrePersist
public
void
prePersist
()
{
Timestamp
timestamp
=
new
Timestamp
(
System
.
currentTimeMillis
());
createdAt
=
timestamp
;
updatedAt
=
timestamp
;
}
@PreUpdate
public
void
preUpdate
()
{
updatedAt
=
new
Timestamp
(
System
.
currentTimeMillis
());
}
}
src/main/java/com/quantgroup/asset/distribution/service/jpa/repository/IAssetAttributeExtendConfigRepository.java
View file @
89aebf3b
...
@@ -7,7 +7,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
...
@@ -7,7 +7,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig
;
public
interface
IAssetAttributeExtendConfigRepository
extends
JpaRepository
<
AssetAttributeExtendConfig
,
Integer
>{
public
interface
IAssetAttributeExtendConfigRepository
extends
JpaRepository
<
AssetAttributeExtendConfig
,
Long
>{
public
List
<
AssetAttributeExtendConfig
>
findByEnableIsTrue
();
public
List
<
AssetAttributeExtendConfig
>
findByEnableIsTrue
();
}
}
src/main/java/com/quantgroup/asset/distribution/service/jpa/repository/IAssetDistributeRecordRepository.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
repository
;
import
java.util.List
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRecord
;
/**
* 资产分发记录Repository
* @author liwenbin
*
*/
public
interface
IAssetDistributeRecordRepository
extends
JpaRepository
<
AssetDistributeRecord
,
Long
>{
public
List
<
AssetDistributeRecord
>
findByAssetNo
(
String
assetNo
);
}
src/main/java/com/quantgroup/asset/distribution/service/jpa/repository/IAssetDistributeRuleConfigRepository.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
repository
;
import
java.util.List
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRuleConfig
;
/**
* 资产分发规则配置表
* @author liwenbin
*
*/
public
interface
IAssetDistributeRuleConfigRepository
extends
JpaRepository
<
AssetDistributeRuleConfig
,
Long
>{
/**
* find所有可用规则
* @return
*/
public
List
<
AssetDistributeRuleConfig
>
findByEnableIsTrueOrderByAssetDistributeRulePriorityAsc
();
}
src/main/java/com/quantgroup/asset/distribution/service/jpa/repository/IAuthorityRepository.java
View file @
89aebf3b
...
@@ -10,7 +10,7 @@ import com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig;
...
@@ -10,7 +10,7 @@ import com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig;
* @author liwenbin
* @author liwenbin
*
*
*/
*/
public
interface
IAuthorityRepository
extends
JpaRepository
<
AuthorityConfig
,
Integer
>{
public
interface
IAuthorityRepository
extends
JpaRepository
<
AuthorityConfig
,
Long
>{
/**
/**
* 根据authKey和authPass查到配置
* 根据authKey和authPass查到配置
...
...
src/main/java/com/quantgroup/asset/distribution/service/jpa/repository/IDistributeFailLogRepository.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
jpa
.
repository
;
import
org.springframework.data.jpa.repository.JpaRepository
;
import
com.quantgroup.asset.distribution.service.jpa.entity.DistributeFailLog
;
/**
* 分发失败Repository
* @author liwenbin
*
*/
public
interface
IDistributeFailLogRepository
extends
JpaRepository
<
DistributeFailLog
,
Long
>{
}
src/main/java/com/quantgroup/asset/distribution/service/notify/INotifyService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
notify
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
/**
* 通知Service
* @author liwenbin
*
*/
public
interface
INotifyService
{
/**
* 通知资金系统
* @param assetForm
*/
public
void
notifyFundServer
(
AssetForm
assetForm
);
}
src/main/java/com/quantgroup/asset/distribution/service/notify/impl/NotifyServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
notify
.
impl
;
import
java.util.Map
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
com.alibaba.fastjson.JSON
;
import
com.quantgroup.asset.distribution.model.form.AssetForm
;
import
com.quantgroup.asset.distribution.service.distribute.IDistributeFailLogService
;
import
com.quantgroup.asset.distribution.service.httpclient.IHttpService
;
import
com.quantgroup.asset.distribution.service.notify.INotifyService
;
import
lombok.extern.slf4j.Slf4j
;
@Slf4j
@Service
public
class
NotifyServiceImpl
implements
INotifyService
{
@Value
(
"${isDebug}"
)
private
Boolean
isDebug
;
@Autowired
private
IHttpService
httpService
;
@Autowired
private
IDistributeFailLogService
distributeFailLogService
;
@Async
@Override
public
void
notifyFundServer
(
AssetForm
assetForm
)
{
try
{
if
(
isDebug
)
{
return
;
}
log
.
info
(
"通知资金系统结果开始, uuid : {}, bizNo : {}, assetNo : {}, callbackUrl : {}, assetForm : {}"
,
assetForm
.
getUuid
(),
assetForm
.
getBizNo
(),
assetForm
.
getAssetNo
(),
assetForm
.
getCallbackUrl
(),
JSON
.
toJSONString
(
assetForm
));
if
(
StringUtils
.
isEmpty
(
assetForm
.
getCallbackUrl
()))
{
log
.
info
(
"通知资金系统结果失败,callbackUrl为空, uuid : {}, bizNo : {}, assetNo : {}, assetForm : {}"
,
assetForm
.
getUuid
(),
assetForm
.
getBizNo
(),
assetForm
.
getAssetNo
(),
JSON
.
toJSONString
(
assetForm
));
return
;
}
Map
<
String
,
String
>
response
=
httpService
.
postHasResponse
(
assetForm
.
getCallbackUrl
(),
assetForm
.
transToNotifyMap
());
log
.
info
(
"通知资金系统结果结束, uuid : {}, bizNo : {}, assetNo : {}, callbackUrl : {}, assetForm : {}, response : {}"
,
assetForm
.
getUuid
(),
assetForm
.
getBizNo
(),
assetForm
.
getAssetNo
(),
assetForm
.
getCallbackUrl
(),
JSON
.
toJSONString
(
assetForm
),
JSON
.
toJSONString
(
response
));
if
(
response
==
null
||
response
.
size
()==
0
||
!
"200"
.
equals
(
response
.
get
(
"statusCode"
))
||
"error"
.
equals
(
response
.
get
(
"response"
)))
{
distributeFailLogService
.
saveDistributeFailLog
(
assetForm
,
"通知资金系统失败."
);
}
}
catch
(
Exception
e
)
{
log
.
info
(
"通知资金系统结果异常, uuid : {}, bizNo : {}, assetNo : {}, callbackUrl : {}, assetForm : {}"
,
assetForm
.
getUuid
(),
assetForm
.
getBizNo
(),
assetForm
.
getAssetNo
(),
assetForm
.
getCallbackUrl
(),
JSON
.
toJSONString
(
assetForm
),
e
);
}
}
}
src/main/java/com/quantgroup/asset/distribution/service/rule/IRuleService.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
rule
;
import
java.util.Map
;
public
interface
IRuleService
{
/**
* 表达式判断
* @param expression 表达式
* @param data 变量数据
* @return 返回true或者false
*/
public
boolean
valid
(
String
expression
,
Map
<
String
,
Object
>
data
);
}
src/main/java/com/quantgroup/asset/distribution/service/rule/impl/RuleServiceImpl.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
service
.
rule
.
impl
;
import
java.math.BigDecimal
;
import
java.util.Map
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
import
com.alibaba.fastjson.JSON
;
import
com.quantgroup.asset.distribution.exception.QGException
;
import
com.quantgroup.asset.distribution.exception.QGExceptionType
;
import
com.quantgroup.asset.distribution.exception.QGPreconditions
;
import
com.quantgroup.asset.distribution.service.rule.IRuleService
;
import
com.quantgroup.asset.distribution.util.calc.Expression
;
import
com.quantgroup.asset.distribution.util.calc.Expression.ExpressionException
;
import
lombok.extern.slf4j.Slf4j
;
/**
* 规则判断
* @author liwenbin
*
*/
@Slf4j
@Service
public
class
RuleServiceImpl
implements
IRuleService
{
@Override
public
boolean
valid
(
String
expression
,
Map
<
String
,
Object
>
data
)
{
try
{
// 如果el表达式为空,返回true
if
(
StringUtils
.
isEmpty
(
expression
))
{
return
true
;
}
Expression
ex
=
new
Expression
(
expression
);
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
data
.
entrySet
())
{
ex
.
with
(
entry
.
getKey
(),
String
.
valueOf
(
entry
.
getValue
()));
}
BigDecimal
res
=
ex
.
eval
();
QGPreconditions
.
checkArgument
(
res
.
compareTo
(
BigDecimal
.
ZERO
)
==
0
||
res
.
compareTo
(
BigDecimal
.
ONE
)
==
0
,
QGExceptionType
.
RULE_CALC_UNKNOW_RESULT
,
expression
);
return
res
.
compareTo
(
BigDecimal
.
ONE
)
==
0
;
}
catch
(
ExpressionException
expressionException
)
{
log
.
error
(
"规则判断出现错误, expression : {}, data : {}"
,
expression
,
JSON
.
toJSONString
(
data
),
expressionException
);
throw
new
QGException
(
QGExceptionType
.
RULE_CALC_ERROR
,
expression
);
}
catch
(
Exception
e
)
{
log
.
error
(
"规则判断出现未知异常, expression : {}, data : {}"
,
expression
,
JSON
.
toJSONString
(
data
),
e
);
throw
new
QGException
(
QGExceptionType
.
RULE_CALC_UNKNOW_ERROR
,
expression
);
}
}
}
src/main/java/com/quantgroup/asset/distribution/util/calc/AbstractFunction.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* Abstract implementation of a direct function.<br>
* <br>
* This abstract implementation does implement lazyEval so that it returns the result of eval.
*/
public
abstract
class
AbstractFunction
extends
AbstractLazyFunction
implements
Function
{
/**
* Creates a new function with given name and parameter count.
*
* @param name The name of the function.
* @param numParams The number of parameters for this function.
* <code>-1</code> denotes a variable number of parameters.
*/
protected
AbstractFunction
(
String
name
,
int
numParams
)
{
super
(
name
,
numParams
);
}
protected
AbstractFunction
(
String
name
,
boolean
booleanFunction
)
{
super
(
name
,
booleanFunction
);
}
/**
* Creates a new function with given name and parameter count.
*
* @param name The name of the function.
* @param numParams The number of parameters for this function.
* <code>-1</code> denotes a variable number of parameters.
* @param booleanFunction Whether this function is a boolean function.
*/
protected
AbstractFunction
(
String
name
,
int
numParams
,
boolean
booleanFunction
)
{
super
(
name
,
numParams
,
booleanFunction
);
}
public
Expression
.
LazyNumber
lazyEval
(
final
List
<
Expression
.
LazyNumber
>
lazyParams
)
{
return
new
Expression
.
LazyNumber
()
{
private
List
<
String
>
params
;
public
String
eval
()
{
return
AbstractFunction
.
this
.
eval
(
getParams
()).
toPlainString
();
}
private
List
<
String
>
getParams
()
{
if
(
params
==
null
)
{
params
=
new
ArrayList
<>();
for
(
Expression
.
LazyNumber
lazyParam
:
lazyParams
)
{
params
.
add
(
lazyParam
.
eval
());
}
}
return
params
;
}
};
}
}
src/main/java/com/quantgroup/asset/distribution/util/calc/AbstractLazyFunction.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
import
java.util.Locale
;
/**
* Abstract implementation of a lazy function which implements all necessary methods with the
* exception of the main logic.
*/
public
abstract
class
AbstractLazyFunction
implements
LazyFunction
{
/**
* Name of this function.
*/
protected
String
name
;
/**
* Number of parameters expected for this function. <code>-1</code> denotes a variable number of
* parameters.
*/
protected
int
numParams
;
/**
* Whether this function is a boolean function.
*/
protected
boolean
booleanFunction
;
/**
* Creates a new function with given name and parameter count.
*
* @param name The name of the function.
* @param numParams The number of parameters for this function.
* <code>-1</code> denotes a variable number of parameters.
* @param booleanFunction Whether this function is a boolean function.
*/
protected
AbstractLazyFunction
(
String
name
,
int
numParams
,
boolean
booleanFunction
)
{
this
.
name
=
name
.
toUpperCase
(
Locale
.
ROOT
);
this
.
numParams
=
numParams
;
this
.
booleanFunction
=
booleanFunction
;
}
/**
* Creates a new function with given name and parameter count.
*
* @param name The name of the function.
* @param numParams The number of parameters for this function.
* <code>-1</code> denotes a variable number of parameters.
*/
protected
AbstractLazyFunction
(
String
name
,
int
numParams
)
{
this
(
name
,
numParams
,
false
);
}
public
AbstractLazyFunction
(
String
name
,
boolean
booleanFunction
)
{
this
.
name
=
name
;
this
.
booleanFunction
=
booleanFunction
;
}
public
String
getName
()
{
return
name
;
}
public
int
getNumParams
()
{
return
numParams
;
}
public
boolean
numParamsVaries
()
{
return
numParams
<
0
;
}
public
boolean
isBooleanFunction
()
{
return
booleanFunction
;
}
}
src/main/java/com/quantgroup/asset/distribution/util/calc/AbstractLazyOperator.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
/**
* Abstract implementation of an operator.
*/
public
abstract
class
AbstractLazyOperator
implements
LazyOperator
{
/**
* This operators name (pattern).
*/
protected
String
oper
;
/**
* Operators precedence.
*/
protected
int
precedence
;
/**
* Operator is left associative.
*/
protected
boolean
leftAssoc
;
/**
* Whether this operator is boolean or not.
*/
protected
boolean
booleanOperator
=
false
;
/**
* Creates a new operator.
*
* @param oper
* The operator name (pattern).
* @param precedence
* The operators precedence.
* @param leftAssoc
* <code>true</code> if the operator is left associative,
* else <code>false</code>.
* @param booleanOperator
* Whether this operator is boolean.
*/
protected
AbstractLazyOperator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
,
boolean
booleanOperator
)
{
this
.
oper
=
oper
;
this
.
precedence
=
precedence
;
this
.
leftAssoc
=
leftAssoc
;
this
.
booleanOperator
=
booleanOperator
;
}
/**
* Creates a new operator.
*
* @param oper
* The operator name (pattern).
* @param precedence
* The operators precedence.
* @param leftAssoc
* <code>true</code> if the operator is left associative,
* else <code>false</code>.
*/
protected
AbstractLazyOperator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
)
{
this
.
oper
=
oper
;
this
.
precedence
=
precedence
;
this
.
leftAssoc
=
leftAssoc
;
}
public
String
getOper
()
{
return
oper
;
}
public
int
getPrecedence
()
{
return
precedence
;
}
public
boolean
isLeftAssoc
()
{
return
leftAssoc
;
}
public
boolean
isBooleanOperator
()
{
return
booleanOperator
;
}
}
src/main/java/com/quantgroup/asset/distribution/util/calc/AbstractOperator.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
/**
* Abstract implementation of an operator.
*/
public
abstract
class
AbstractOperator
extends
AbstractLazyOperator
implements
Operator
{
/**
* Creates a new operator.
*
* @param oper The operator name (pattern).
* @param precedence The operators precedence.
* @param leftAssoc <code>true</code> if the operator is left associative, else
* <code>false</code>.
* @param booleanOperator Whether this operator is boolean.
*/
protected
AbstractOperator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
,
boolean
booleanOperator
)
{
super
(
oper
,
precedence
,
leftAssoc
,
booleanOperator
);
}
/**
* Creates a new operator.
*
* @param oper The operator name (pattern).
* @param precedence The operators precedence.
* @param leftAssoc <code>true</code> if the operator is left associative, else
* <code>false</code>.
*/
protected
AbstractOperator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
)
{
super
(
oper
,
precedence
,
leftAssoc
);
}
public
Expression
.
LazyNumber
eval
(
final
Expression
.
LazyNumber
v1
,
final
Expression
.
LazyNumber
v2
)
{
return
()
->
AbstractOperator
.
this
.
eval
(
v1
.
eval
(),
v2
.
eval
()).
toPlainString
();
}
}
src/main/java/com/quantgroup/asset/distribution/util/calc/AbstractUnaryOperator.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
import
java.math.BigDecimal
;
/**
* Abstract implementation of an unary operator.<br>
* <br>
* This abstract implementation implements eval so that it forwards its first parameter to
* evalUnary.
*/
public
abstract
class
AbstractUnaryOperator
extends
AbstractOperator
{
/**
* Creates a new operator.
*
* @param oper The operator name (pattern).
* @param precedence The operators precedence.
* @param leftAssoc <code>true</code> if the operator is left associative, else
* <code>false</code>.
*/
protected
AbstractUnaryOperator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
)
{
super
(
oper
,
precedence
,
leftAssoc
);
}
public
Expression
.
LazyNumber
eval
(
final
Expression
.
LazyNumber
v1
,
final
Expression
.
LazyNumber
v2
)
{
if
(
v2
!=
null
)
{
throw
new
Expression
.
ExpressionException
(
"Did not expect a second parameter for unary operator"
);
}
return
()
->
AbstractUnaryOperator
.
this
.
evalUnary
(
v1
.
eval
()).
toPlainString
();
}
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
if
(
v2
!=
null
)
{
throw
new
Expression
.
ExpressionException
(
"Did not expect a second parameter for unary operator"
);
}
return
evalUnary
(
v1
);
}
/**
* Implementation of this unary operator.
*
* @param v1 The parameter.
* @return The result of the operation.
*/
public
abstract
BigDecimal
evalUnary
(
String
v1
);
}
src/main/java/com/quantgroup/asset/distribution/util/calc/Expression.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
/*
* Copyright 2012-2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
import
com.google.common.collect.Sets
;
import
lombok.Getter
;
import
lombok.Setter
;
import
java.math.BigDecimal
;
import
java.math.BigInteger
;
import
java.math.MathContext
;
import
java.math.RoundingMode
;
import
java.util.*
;
/**
* <h1>EvalEx - Java Expression Evaluator</h1>
*
* <h2>Introduction</h2> EvalEx is a handy expression evaluator for Java, that
* allows to evaluate simple mathematical and boolean expressions. <br> For more information, see:
* <a href="https://github.com/uklimaschewski/EvalEx">EvalEx GitHub
* repository</a>
* <ul>
* <li>The software is licensed under the MIT Open Source license (see <a href=
* "https://raw.githubusercontent.com/uklimaschewski/EvalEx/master/LICENSE">LICENSE file</a>).</li>
* <li>The *power of* operator (^) implementation was copied from <a href=
* "http://stackoverflow.com/questions/3579779/how-to-do-a-fractional-power-on-bigdecimal-in-java">Stack
* Overflow</a>. Thanks to Gene Marin.</li>
* <li>The SQRT() function implementation was taken from the book <a href=
* "http://www.amazon.de/Java-Number-Cruncher-Programmers-Numerical/dp/0130460419">The Java
* Programmers Guide To numerical Computing</a> (Ronald Mak, 2002).</li>
* </ul>
*
* @authors Thanks to all who contributed to this project: <a href= "https://github.com/uklimaschewski/EvalEx/graphs/contributors">Contributors</a>
* @see <a href="https://github.com/uklimaschewski/EvalEx">GitHub repository</a>
*/
@Getter
@Setter
public
class
Expression
{
//private Map<String, String> supplement;//补充信息,用于处理特征,如果字符在map之中,则直接将字符串替换为特征值。
/**
* Unary operators precedence: + and - as prefix
*/
public
static
final
int
OPERATOR_PRECEDENCE_UNARY
=
60
;
/**
* Equality operators precedence: =, ==, !=. <>
*/
public
static
final
int
OPERATOR_PRECEDENCE_EQUALITY
=
7
;
/**
* Comparative operators precedence: <,>,<=,>=
*/
public
static
final
int
OPERATOR_PRECEDENCE_COMPARISON
=
10
;
/**
* Or operator precedence: ||
*/
public
static
final
int
OPERATOR_PRECEDENCE_OR
=
2
;
/**
* And operator precedence: &&
*/
public
static
final
int
OPERATOR_PRECEDENCE_AND
=
4
;
/**
* Power operator precedence: ^
*/
public
static
final
int
OPERATOR_PRECEDENCE_POWER
=
40
;
/**
* Multiplicative operators precedence: *,/,%
*/
public
static
final
int
OPERATOR_PRECEDENCE_MULTIPLICATIVE
=
30
;
/**
* Additive operators precedence: + and -
*/
public
static
final
int
OPERATOR_PRECEDENCE_ADDITIVE
=
20
;
/**
* Definition of PI as a constant, can be used in expressions as variable.
*/
public
static
final
BigDecimal
PI
=
new
BigDecimal
(
"3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
);
/**
* Definition of e: "Euler's number" as a constant, can be used in expressions as variable.
*/
public
static
final
BigDecimal
e
=
new
BigDecimal
(
"2.71828182845904523536028747135266249775724709369995957496696762772407663"
);
/**
* The {@link MathContext} to use for calculations.
*/
private
MathContext
mc
=
null
;
/**
* The characters (other than letters and digits) allowed as the first character in a variable.
*/
private
String
firstVarChars
=
"_"
;
/**
* The characters (other than letters and digits) allowed as the second or subsequent characters
* in a variable.
*/
private
String
varChars
=
"_"
;
/**
* The original infix expression.
*/
private
final
String
originalExpression
;
/**
* The current infix expression, with optional variable substitutions.
*/
private
String
expression
=
null
;
/**
* The cached RPN (Reverse Polish Notation) of the expression.
*/
private
List
<
Token
>
rpn
=
null
;
/**
* All defined operators with name and implementation.
*/
private
Map
<
String
,
LazyOperator
>
operators
=
new
TreeMap
<
String
,
LazyOperator
>(
String
.
CASE_INSENSITIVE_ORDER
);
/**
* All defined functions with name and implementation.
*/
private
Map
<
String
,
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
LazyFunction
>
functions
=
new
TreeMap
(
String
.
CASE_INSENSITIVE_ORDER
);
/**
* All defined variables with name and value.
*/
private
Map
<
String
,
LazyNumber
>
variables
=
new
TreeMap
<
String
,
LazyNumber
>(
String
.
CASE_INSENSITIVE_ORDER
);
/**
* What character to use for decimal separators.
*/
private
static
final
char
decimalSeparator
=
'.'
;
/**
* What character to use for minus sign (negative values).
*/
private
static
final
char
minusSign
=
'-'
;
/**
* The BigDecimal representation of the left parenthesis, used for parsing varying numbers of
* function parameters.
*/
private
static
final
LazyNumber
PARAMS_START
=
()
->
null
;
/**
* The expression evaluators exception class.
*/
public
static
class
ExpressionException
extends
RuntimeException
{
private
static
final
long
serialVersionUID
=
1118142866870779047L
;
public
ExpressionException
(
String
message
)
{
super
(
message
);
}
}
/**
* LazyNumber interface created for lazily evaluated functions
*/
public
interface
LazyNumber
{
String
eval
();
}
/**
* Construct a LazyNumber from a BigDecimal
*/
private
LazyNumber
CreateLazyNumber
(
final
String
string
)
{
return
()
->
string
;
}
public
abstract
class
LazyFunction
extends
AbstractLazyFunction
{
/**
* Creates a new function with given name and parameter count.
*
* @param name The name of the function.
* @param numParams The number of parameters for this function.
* <code>-1</code> denotes a variable number of parameters.
* @param booleanFunction Whether this function is a boolean function.
*/
public
LazyFunction
(
String
name
,
int
numParams
,
boolean
booleanFunction
)
{
super
(
name
,
numParams
,
booleanFunction
);
}
/**
* Creates a new function with given name and parameter count.
*
* @param name The name of the function.
* @param numParams The number of parameters for this function.
* <code>-1</code> denotes a variable number of parameters.
*/
public
LazyFunction
(
String
name
,
int
numParams
)
{
super
(
name
,
numParams
);
}
}
/**
* Abstract definition of a supported expression function. A function is defined by a name, the
* number of parameters and the actual processing implementation.
*/
public
abstract
class
Function
extends
AbstractFunction
{
public
Function
(
String
name
,
boolean
booleanFunction
)
{
super
(
name
,
booleanFunction
);
}
public
Function
(
String
name
,
int
numParams
)
{
super
(
name
,
numParams
);
}
public
Function
(
String
name
,
int
numParams
,
boolean
booleanFunction
)
{
super
(
name
,
numParams
,
booleanFunction
);
}
}
/**
* Abstract definition of a supported operator. An operator is defined by its name (pattern),
* precedence and if it is left- or right associative.
*/
public
abstract
class
Operator
extends
AbstractOperator
{
/**
* Creates a new operator.
*
* @param oper The operator name (pattern).
* @param precedence The operators precedence.
* @param leftAssoc <code>true</code> if the operator is left associative, else
* <code>false</code>.
* @param booleanOperator Whether this operator is boolean.
*/
public
Operator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
,
boolean
booleanOperator
)
{
super
(
oper
,
precedence
,
leftAssoc
,
booleanOperator
);
}
/**
* Creates a new operator.
*
* @param oper The operator name (pattern).
* @param precedence The operators precedence.
* @param leftAssoc <code>true</code> if the operator is left associative, else
* <code>false</code>.
*/
public
Operator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
)
{
super
(
oper
,
precedence
,
leftAssoc
);
}
}
public
abstract
class
UnaryOperator
extends
AbstractUnaryOperator
{
public
UnaryOperator
(
String
oper
,
int
precedence
,
boolean
leftAssoc
)
{
super
(
oper
,
precedence
,
leftAssoc
);
}
}
enum
TokenType
{
VARIABLE
,
FUNCTION
,
LITERAL
,
OPERATOR
,
UNARY_OPERATOR
,
OPEN_PAREN
,
COMMA
,
CLOSE_PAREN
,
HEX_LITERAL
,
STRINGPARAM
}
class
Token
{
public
String
surface
=
""
;
public
TokenType
type
;
public
int
pos
;
public
void
append
(
char
c
)
{
surface
+=
c
;
}
public
void
append
(
String
s
)
{
surface
+=
s
;
}
public
char
charAt
(
int
pos
)
{
return
surface
.
charAt
(
pos
);
}
public
int
length
()
{
return
surface
.
length
();
}
@Override
public
String
toString
()
{
return
surface
;
}
}
/**
* Expression tokenizer that allows to iterate over a {@link String} expression token by token.
* Blank characters will be skipped.
*/
private
class
Tokenizer
implements
Iterator
<
Token
>
{
/**
* Actual position in expression string.
*/
private
int
pos
=
0
;
/**
* The original input expression.
*/
private
String
input
;
/**
* The previous token or <code>null</code> if none.
*/
private
Token
previousToken
;
/**
* Creates a new tokenizer for an expression.
*
* @param input The expression string.
*/
public
Tokenizer
(
String
input
)
{
this
.
input
=
input
.
trim
();
}
@Override
public
boolean
hasNext
()
{
return
(
pos
<
input
.
length
());
}
/**
* Peek at the next character, without advancing the iterator.
*
* @return The next character or character 0, if at end of string.
*/
private
char
peekNextChar
()
{
if
(
pos
<
(
input
.
length
()
-
1
))
{
return
input
.
charAt
(
pos
+
1
);
}
else
{
return
0
;
}
}
private
boolean
isHexDigit
(
char
ch
)
{
return
ch
==
'x'
||
ch
==
'X'
||
(
ch
>=
'0'
&&
ch
<=
'9'
)
||
(
ch
>=
'a'
&&
ch
<=
'f'
)
||
(
ch
>=
'A'
&&
ch
<=
'F'
);
}
@Override
public
Token
next
()
{
Token
token
=
new
Token
();
if
(
pos
>=
input
.
length
())
{
return
previousToken
=
null
;
}
char
ch
=
input
.
charAt
(
pos
);
while
(
Character
.
isWhitespace
(
ch
)
&&
pos
<
input
.
length
())
{
ch
=
input
.
charAt
(++
pos
);
}
token
.
pos
=
pos
;
boolean
isHex
=
false
;
//added by liuhong 单独处理@/!@
if
(
previousToken
!=
null
&&
(
"@"
.
equalsIgnoreCase
(
previousToken
.
surface
)
||
"!@"
.
equalsIgnoreCase
(
previousToken
.
surface
)))
{
while
(
pos
<
input
.
length
()
&&
!
operators
.
containsKey
(
ch
+
""
)
&&
!
operators
.
containsKey
(
ch
+
""
+
peekNextChar
())
&&
ch
!=
'('
&&
ch
!=
')'
)
{
token
.
append
(
input
.
charAt
(
pos
++));
ch
=
pos
==
input
.
length
()
?
0
:
input
.
charAt
(
pos
);
}
token
.
type
=
TokenType
.
LITERAL
;
}
else
if
(
Character
.
isDigit
(
ch
)
||
(
ch
==
decimalSeparator
&&
Character
.
isDigit
(
peekNextChar
())))
{
if
(
ch
==
'0'
&&
(
peekNextChar
()
==
'x'
||
peekNextChar
()
==
'X'
))
{
isHex
=
true
;
}
while
((
isHex
&&
isHexDigit
(
ch
))
||
(
Character
.
isDigit
(
ch
)
||
ch
==
decimalSeparator
||
ch
==
'e'
||
ch
==
'E'
||
(
ch
==
minusSign
&&
token
.
length
()
>
0
&&
(
'e'
==
token
.
charAt
(
token
.
length
()
-
1
)
||
'E'
==
token
.
charAt
(
token
.
length
()
-
1
)))
||
(
ch
==
'+'
&&
token
.
length
()
>
0
&&
(
'e'
==
token
.
charAt
(
token
.
length
()
-
1
)
||
'E'
==
token
.
charAt
(
token
.
length
()
-
1
))))
&&
(
pos
<
input
.
length
()))
{
token
.
append
(
input
.
charAt
(
pos
++));
ch
=
pos
==
input
.
length
()
?
0
:
input
.
charAt
(
pos
);
}
// 增加支持以数字开头的变量命名
if
(
pos
<
input
.
length
()
&&
(
varChars
.
indexOf
((
ch
=
input
.
charAt
(
pos
)))
>=
0
||
Character
.
isLetter
(
ch
)))
{
while
((
'#'
==
ch
||
Character
.
isLetter
(
ch
)
||
Character
.
isDigit
(
ch
)
||
varChars
.
indexOf
(
ch
)
>=
0
||
token
.
length
()
==
0
&&
firstVarChars
.
indexOf
(
ch
)
>=
0
)
&&
(
pos
<
input
.
length
()))
{
token
.
append
(
input
.
charAt
(
pos
++));
ch
=
pos
==
input
.
length
()
?
0
:
input
.
charAt
(
pos
);
}
// Remove optional white spaces after function or variable name
if
(
Character
.
isWhitespace
(
ch
))
{
while
(
Character
.
isWhitespace
(
ch
)
&&
pos
<
input
.
length
())
{
ch
=
input
.
charAt
(
pos
++);
}
pos
--;
}
token
.
type
=
ch
==
'('
?
TokenType
.
FUNCTION
:
variables
.
containsKey
(
token
.
surface
)
?
TokenType
.
VARIABLE
:
TokenType
.
LITERAL
;
}
else
{
token
.
type
=
isHex
?
TokenType
.
HEX_LITERAL
:
TokenType
.
LITERAL
;
}
}
else
if
(
ch
==
'"'
)
{
pos
++;
if
(
previousToken
.
type
!=
TokenType
.
STRINGPARAM
)
{
ch
=
input
.
charAt
(
pos
);
while
(
ch
!=
'"'
)
{
token
.
append
(
input
.
charAt
(
pos
++));
ch
=
pos
==
input
.
length
()
?
0
:
input
.
charAt
(
pos
);
}
token
.
type
=
TokenType
.
STRINGPARAM
;
}
else
{
return
next
();
}
}
else
if
(
Character
.
isLetter
(
ch
)
||
firstVarChars
.
indexOf
(
ch
)
>=
0
)
{
//added by liuhong 此处兼容特征格式 aa#bb
while
((
'#'
==
ch
||
Character
.
isLetter
(
ch
)
||
Character
.
isDigit
(
ch
)
||
varChars
.
indexOf
(
ch
)
>=
0
||
token
.
length
()
==
0
&&
firstVarChars
.
indexOf
(
ch
)
>=
0
)
&&
(
pos
<
input
.
length
()))
{
token
.
append
(
input
.
charAt
(
pos
++));
ch
=
pos
==
input
.
length
()
?
0
:
input
.
charAt
(
pos
);
}
// Remove optional white spaces after function or variable name
if
(
Character
.
isWhitespace
(
ch
))
{
while
(
Character
.
isWhitespace
(
ch
)
&&
pos
<
input
.
length
())
{
ch
=
input
.
charAt
(
pos
++);
}
pos
--;
}
token
.
type
=
ch
==
'('
?
TokenType
.
FUNCTION
:
variables
.
containsKey
(
token
.
surface
)
?
TokenType
.
VARIABLE
:
TokenType
.
LITERAL
;
}
else
if
(
ch
==
'('
||
ch
==
')'
||
ch
==
','
)
{
if
(
ch
==
'('
)
{
token
.
type
=
TokenType
.
OPEN_PAREN
;
}
else
if
(
ch
==
')'
)
{
token
.
type
=
TokenType
.
CLOSE_PAREN
;
}
else
{
token
.
type
=
TokenType
.
COMMA
;
}
token
.
append
(
ch
);
pos
++;
}
else
{
String
greedyMatch
=
""
;
int
initialPos
=
pos
;
ch
=
input
.
charAt
(
pos
);
int
validOperatorSeenUntil
=
-
1
;
while
(!
Character
.
isLetter
(
ch
)
&&
!
Character
.
isDigit
(
ch
)
&&
firstVarChars
.
indexOf
(
ch
)
<
0
&&
!
Character
.
isWhitespace
(
ch
)
&&
ch
!=
'('
&&
ch
!=
')'
&&
ch
!=
','
&&
(
pos
<
input
.
length
()))
{
greedyMatch
+=
ch
;
pos
++;
if
(
operators
.
containsKey
(
greedyMatch
))
{
validOperatorSeenUntil
=
pos
;
}
ch
=
pos
==
input
.
length
()
?
0
:
input
.
charAt
(
pos
);
}
if
(
validOperatorSeenUntil
!=
-
1
)
{
token
.
append
(
input
.
substring
(
initialPos
,
validOperatorSeenUntil
));
pos
=
validOperatorSeenUntil
;
}
else
{
token
.
append
(
greedyMatch
);
}
if
(
previousToken
==
null
||
previousToken
.
type
==
TokenType
.
OPERATOR
||
previousToken
.
type
==
TokenType
.
OPEN_PAREN
||
previousToken
.
type
==
TokenType
.
COMMA
||
previousToken
.
type
==
TokenType
.
UNARY_OPERATOR
)
{
token
.
surface
+=
"u"
;
token
.
type
=
TokenType
.
UNARY_OPERATOR
;
}
else
{
token
.
type
=
TokenType
.
OPERATOR
;
}
}
return
previousToken
=
token
;
}
@Override
public
void
remove
()
{
throw
new
ExpressionException
(
"remove() not supported"
);
}
}
/**
* Creates a new expression instance from an expression string with a given default match context
* of {@link MathContext#DECIMAL32}.
*
* @param expression The expression. E.g. <code>"2.4*sin(3)/(2-4)"</code> or
* <code>"sin(y)>0 & max(z, 3)>3"</code>
*/
public
Expression
(
String
expression
)
{
//this(expression, MathContext.DECIMAL32);
this
(
expression
,
new
MathContext
(
6
,
RoundingMode
.
HALF_UP
));
}
/**
* Creates a new expression instance from an expression string with a given default match
* context.
*
* @param expression The expression. E.g. <code>"2.4*sin(3)/(2-4)"</code> or
* <code>"sin(y)>0 & max(z, 3)>3"</code>
* @param defaultMathContext The {@link MathContext} to use by default.
*/
public
Expression
(
String
expression
,
MathContext
defaultMathContext
)
{
this
.
mc
=
defaultMathContext
;
this
.
expression
=
expression
;
this
.
originalExpression
=
expression
;
addOperator
(
new
Operator
(
"+"
,
OPERATOR_PRECEDENCE_ADDITIVE
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
add
(
new
BigDecimal
(
v2
),
mc
);
}
});
addOperator
(
new
Operator
(
"-"
,
OPERATOR_PRECEDENCE_ADDITIVE
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
subtract
(
new
BigDecimal
(
v2
),
mc
);
}
});
addOperator
(
new
Operator
(
"*"
,
OPERATOR_PRECEDENCE_MULTIPLICATIVE
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
multiply
(
new
BigDecimal
(
v2
),
mc
);
}
});
addOperator
(
new
Operator
(
"/"
,
OPERATOR_PRECEDENCE_MULTIPLICATIVE
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
divide
(
new
BigDecimal
(
v2
),
mc
);
}
});
addOperator
(
new
Operator
(
"%"
,
OPERATOR_PRECEDENCE_MULTIPLICATIVE
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
remainder
(
new
BigDecimal
(
v2
),
mc
);
}
});
addOperator
(
new
Operator
(
"^"
,
OPERATOR_PRECEDENCE_POWER
,
false
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
/*-
* Thanks to Gene Marin:
* http://stackoverflow.com/questions/3579779/how-to-do-a-fractional-power-on-bigdecimal-in-java
*/
int
signOf2
=
new
BigDecimal
(
v2
).
signum
();
double
dn1
=
new
BigDecimal
(
v1
).
doubleValue
();
v2
=
new
BigDecimal
(
v2
).
multiply
(
new
BigDecimal
(
signOf2
))
.
toPlainString
();
// n2 is now positive
BigDecimal
remainderOf2
=
new
BigDecimal
(
v2
).
remainder
(
BigDecimal
.
ONE
);
BigDecimal
n2IntPart
=
new
BigDecimal
(
v2
).
subtract
(
remainderOf2
);
BigDecimal
intPow
=
new
BigDecimal
(
v1
).
pow
(
n2IntPart
.
intValueExact
(),
mc
);
BigDecimal
doublePow
=
new
BigDecimal
(
Math
.
pow
(
dn1
,
remainderOf2
.
doubleValue
()));
BigDecimal
result
=
intPow
.
multiply
(
doublePow
,
mc
);
if
(
signOf2
==
-
1
)
{
result
=
BigDecimal
.
ONE
.
divide
(
result
,
mc
.
getPrecision
(),
RoundingMode
.
HALF_UP
);
}
return
result
;
}
});
addOperator
(
new
Operator
(
"&&"
,
OPERATOR_PRECEDENCE_AND
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
boolean
b1
=
new
BigDecimal
(
v1
).
compareTo
(
BigDecimal
.
ZERO
)
!=
0
;
if
(!
b1
)
{
return
BigDecimal
.
ZERO
;
}
boolean
b2
=
new
BigDecimal
(
v2
).
compareTo
(
BigDecimal
.
ZERO
)
!=
0
;
return
b2
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
"||"
,
OPERATOR_PRECEDENCE_OR
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
boolean
b1
=
new
BigDecimal
(
v1
).
compareTo
(
BigDecimal
.
ZERO
)
!=
0
;
if
(
b1
)
{
return
BigDecimal
.
ONE
;
}
boolean
b2
=
new
BigDecimal
(
v2
).
compareTo
(
BigDecimal
.
ZERO
)
!=
0
;
return
b2
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
">"
,
OPERATOR_PRECEDENCE_COMPARISON
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
compareTo
(
new
BigDecimal
(
v2
))
==
1
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
">="
,
OPERATOR_PRECEDENCE_COMPARISON
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
compareTo
(
new
BigDecimal
(
v2
))
>=
0
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
"<"
,
OPERATOR_PRECEDENCE_COMPARISON
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
compareTo
(
new
BigDecimal
(
v2
))
==
-
1
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
"<="
,
OPERATOR_PRECEDENCE_COMPARISON
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
new
BigDecimal
(
v1
).
compareTo
(
new
BigDecimal
(
v2
))
<=
0
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
"="
,
OPERATOR_PRECEDENCE_EQUALITY
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
if
(
v1
==
v2
)
{
return
BigDecimal
.
ONE
;
}
if
(
v1
==
null
||
v2
==
null
)
{
return
BigDecimal
.
ZERO
;
}
return
new
BigDecimal
(
v1
).
compareTo
(
new
BigDecimal
(
v2
))
==
0
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
"=="
,
OPERATOR_PRECEDENCE_EQUALITY
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
return
((
Operator
)
operators
.
get
(
"="
)).
eval
(
v1
,
v2
);
}
});
addOperator
(
new
Operator
(
"!="
,
OPERATOR_PRECEDENCE_EQUALITY
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
if
(
v1
==
v2
)
{
return
BigDecimal
.
ZERO
;
}
if
(
v1
==
null
||
v2
==
null
)
{
return
BigDecimal
.
ONE
;
}
return
new
BigDecimal
(
v1
).
compareTo
(
new
BigDecimal
(
v2
))
!=
0
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addOperator
(
new
Operator
(
"<>"
,
OPERATOR_PRECEDENCE_EQUALITY
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
return
((
Operator
)
operators
.
get
(
"!="
)).
eval
(
v1
,
v2
);
}
});
//新增运算符 @ 含义:包含 added by liuhong
addOperator
(
new
Operator
(
"@"
,
OPERATOR_PRECEDENCE_EQUALITY
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
List
<
String
>
target
=
Arrays
.
asList
(
v2
.
trim
().
split
(
","
));
return
target
.
contains
(
v1
)
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
//不包含
addOperator
(
new
Operator
(
"!@"
,
OPERATOR_PRECEDENCE_EQUALITY
,
false
,
true
)
{
@Override
public
BigDecimal
eval
(
String
v1
,
String
v2
)
{
assertNotNull
(
v1
,
v2
);
List
<
String
>
target
=
Arrays
.
asList
(
v2
.
trim
().
split
(
","
));
return
target
.
contains
(
v1
)
?
BigDecimal
.
ZERO
:
BigDecimal
.
ONE
;
}
});
addOperator
(
new
UnaryOperator
(
"-"
,
OPERATOR_PRECEDENCE_UNARY
,
false
)
{
@Override
public
BigDecimal
evalUnary
(
String
v1
)
{
return
new
BigDecimal
(
v1
).
multiply
(
new
BigDecimal
(-
1
));
}
});
addOperator
(
new
UnaryOperator
(
"+"
,
OPERATOR_PRECEDENCE_UNARY
,
false
)
{
@Override
public
BigDecimal
evalUnary
(
String
v1
)
{
return
new
BigDecimal
(
v1
).
multiply
(
BigDecimal
.
ONE
);
}
});
addFunction
(
new
Function
(
"FACT"
,
1
,
false
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
int
number
=
new
BigDecimal
(
parameters
.
get
(
0
)).
intValue
();
BigDecimal
factorial
=
BigDecimal
.
ONE
;
for
(
int
i
=
1
;
i
<=
number
;
i
++)
{
factorial
=
factorial
.
multiply
(
new
BigDecimal
(
i
));
}
return
factorial
;
}
});
addFunction
(
new
Function
(
"NOT"
,
1
,
true
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
boolean
zero
=
new
BigDecimal
(
parameters
.
get
(
0
)).
compareTo
(
BigDecimal
.
ZERO
)
==
0
;
return
zero
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
addLazyFunction
(
new
LazyFunction
(
"IF"
,
3
)
{
@Override
public
LazyNumber
lazyEval
(
List
<
LazyNumber
>
lazyParams
)
{
BigDecimal
result
=
new
BigDecimal
(
lazyParams
.
get
(
0
).
eval
());
assertNotNull
(
result
);
boolean
isTrue
=
result
.
compareTo
(
BigDecimal
.
ZERO
)
!=
0
;
return
isTrue
?
lazyParams
.
get
(
1
)
:
lazyParams
.
get
(
2
);
}
});
addFunction
(
new
Function
(
"RANDOM"
,
0
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
double
d
=
Math
.
random
();
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"SIN"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
sin
(
Math
.
toRadians
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"COS"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
cos
(
Math
.
toRadians
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"TAN"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
tan
(
Math
.
toRadians
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"ASIN"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
toDegrees
(
Math
.
asin
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"ACOS"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
toDegrees
(
Math
.
acos
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"ATAN"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
toDegrees
(
Math
.
atan
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"ATAN2"
,
2
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
),
parameters
.
get
(
1
));
double
d
=
Math
.
toDegrees
(
Math
.
atan2
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
(),
new
BigDecimal
(
parameters
.
get
(
1
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"SINH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
sinh
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"COSH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
cosh
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"TANH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
tanh
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"SEC"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: sec(x) = 1 / cos(x) */
double
one
=
1
;
double
d
=
Math
.
cos
(
Math
.
toRadians
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
((
one
/
d
),
mc
);
}
});
addFunction
(
new
Function
(
"CSC"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: csc(x) = 1 / sin(x) */
double
one
=
1
;
double
d
=
Math
.
sin
(
Math
.
toRadians
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
((
one
/
d
),
mc
);
}
});
addFunction
(
new
Function
(
"SECH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: sech(x) = 1 / cosh(x) */
double
one
=
1
;
double
d
=
Math
.
cosh
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
((
one
/
d
),
mc
);
}
});
addFunction
(
new
Function
(
"CSCH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: csch(x) = 1 / sinh(x) */
double
one
=
1
;
double
d
=
Math
.
sinh
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
((
one
/
d
),
mc
);
}
});
addFunction
(
new
Function
(
"COT"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: cot(x) = cos(x) / sin(x) = 1 / tan(x) */
double
one
=
1
;
double
d
=
Math
.
tan
(
Math
.
toRadians
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
((
one
/
d
),
mc
);
}
});
addFunction
(
new
Function
(
"ACOT"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: acot(x) = atan(1/x) */
if
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()
==
0
)
{
throw
new
ExpressionException
(
"Number must not be 0"
);
}
double
d
=
Math
.
toDegrees
(
Math
.
atan
(
1
/
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"COTH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: coth(x) = 1 / tanh(x) */
double
one
=
1
;
double
d
=
Math
.
tanh
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
((
one
/
d
),
mc
);
}
});
addFunction
(
new
Function
(
"ASINH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: asinh(x) = ln(x + sqrt(x^2 + 1)) */
double
d
=
Math
.
log
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()
+
(
Math
.
sqrt
(
Math
.
pow
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
(),
2
)
+
1
)));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"ACOSH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: acosh(x) = ln(x + sqrt(x^2 - 1)) */
if
(
Double
.
compare
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
(),
1
)
<
0
)
{
throw
new
ExpressionException
(
"Number must be x >= 1"
);
}
double
d
=
Math
.
log
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()
+
(
Math
.
sqrt
(
Math
.
pow
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
(),
2
)
-
1
)));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"ATANH"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/** Formula: atanh(x) = 0.5*ln((1 + x)/(1 - x)) */
if
(
Math
.
abs
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
())
>
1
||
Math
.
abs
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
())
==
1
)
{
throw
new
ExpressionException
(
"Number must be |x| < 1"
);
}
double
d
=
0.5
*
Math
.
log
(
(
1
+
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
())
/
(
1
-
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
()));
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"RAD"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
toRadians
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"DEG"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
toDegrees
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"MAX"
,
-
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
if
(
parameters
.
size
()
==
0
)
{
throw
new
ExpressionException
(
"MAX requires at least one parameter"
);
}
BigDecimal
max
=
null
;
for
(
String
parameter
:
parameters
)
{
assertNotNull
(
parameter
);
if
(
max
==
null
||
new
BigDecimal
(
parameter
).
compareTo
(
max
)
>
0
)
{
max
=
new
BigDecimal
(
parameter
);
}
}
return
max
;
}
});
addFunction
(
new
Function
(
"MIN"
,
-
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
if
(
parameters
.
size
()
==
0
)
{
throw
new
ExpressionException
(
"MIN requires at least one parameter"
);
}
BigDecimal
min
=
null
;
for
(
String
parameter
:
parameters
)
{
assertNotNull
(
parameter
);
if
(
min
==
null
||
new
BigDecimal
(
parameter
).
compareTo
(
min
)
<
0
)
{
min
=
new
BigDecimal
(
parameter
);
}
}
return
min
;
}
});
addFunction
(
new
Function
(
"ABS"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
return
new
BigDecimal
(
parameters
.
get
(
0
)).
abs
(
mc
);
}
});
addFunction
(
new
Function
(
"LOG"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
log
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"LOG10"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
double
d
=
Math
.
log10
(
new
BigDecimal
(
parameters
.
get
(
0
)).
doubleValue
());
return
new
BigDecimal
(
d
,
mc
);
}
});
addFunction
(
new
Function
(
"ROUND"
,
2
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
),
parameters
.
get
(
1
));
BigDecimal
toRound
=
new
BigDecimal
(
parameters
.
get
(
0
));
int
precision
=
new
BigDecimal
(
parameters
.
get
(
1
)).
intValue
();
return
toRound
.
setScale
(
precision
,
mc
.
getRoundingMode
());
}
});
addFunction
(
new
Function
(
"FLOOR"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
BigDecimal
toRound
=
new
BigDecimal
(
parameters
.
get
(
0
));
return
toRound
.
setScale
(
0
,
RoundingMode
.
FLOOR
);
}
});
addFunction
(
new
Function
(
"CEILING"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
BigDecimal
toRound
=
new
BigDecimal
(
parameters
.
get
(
0
));
return
toRound
.
setScale
(
0
,
RoundingMode
.
CEILING
);
}
});
addFunction
(
new
Function
(
"SQRT"
,
1
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
/*
* From The Java Programmers Guide To numerical Computing
* (Ronald Mak, 2003)
*/
BigDecimal
x
=
new
BigDecimal
(
parameters
.
get
(
0
));
if
(
x
.
compareTo
(
BigDecimal
.
ZERO
)
==
0
)
{
return
new
BigDecimal
(
0
);
}
if
(
x
.
signum
()
<
0
)
{
throw
new
ExpressionException
(
"Argument to SQRT() function must not be negative"
);
}
BigInteger
n
=
x
.
movePointRight
(
mc
.
getPrecision
()
<<
1
).
toBigInteger
();
int
bits
=
(
n
.
bitLength
()
+
1
)
>>
1
;
BigInteger
ix
=
n
.
shiftRight
(
bits
);
BigInteger
ixPrev
;
BigInteger
test
;
do
{
ixPrev
=
ix
;
ix
=
ix
.
add
(
n
.
divide
(
ix
)).
shiftRight
(
1
);
// Give other threads a chance to work;
Thread
.
yield
();
test
=
ix
.
subtract
(
ixPrev
).
abs
();
}
while
(
test
.
compareTo
(
BigInteger
.
ZERO
)
!=
0
&&
test
.
compareTo
(
BigInteger
.
ONE
)
!=
0
);
return
new
BigDecimal
(
ix
,
mc
.
getPrecision
());
}
});
//添加函数in added by liuhong
addFunction
(
new
Function
(
"IN"
,
true
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
String
target
=
parameters
.
get
(
0
);
List
<
String
>
source
=
parameters
.
subList
(
1
,
parameters
.
size
());
return
source
.
contains
(
target
)
?
BigDecimal
.
ONE
:
BigDecimal
.
ZERO
;
}
});
//添加函数 not in
addFunction
(
new
Function
(
"NOTIN"
,
true
)
{
@Override
public
BigDecimal
eval
(
List
<
String
>
parameters
)
{
assertNotNull
(
parameters
.
get
(
0
));
String
target
=
parameters
.
get
(
0
);
List
<
String
>
source
=
parameters
.
subList
(
1
,
parameters
.
size
());
return
source
.
contains
(
target
)
?
BigDecimal
.
ZERO
:
BigDecimal
.
ONE
;
}
});
variables
.
put
(
"e"
,
CreateLazyNumber
(
e
.
toPlainString
()));
variables
.
put
(
"PI"
,
CreateLazyNumber
(
PI
.
toPlainString
()));
variables
.
put
(
"NULL"
,
null
);
variables
.
put
(
"TRUE"
,
CreateLazyNumber
(
BigDecimal
.
ONE
.
toPlainString
()));
variables
.
put
(
"FALSE"
,
CreateLazyNumber
(
BigDecimal
.
ZERO
.
toPlainString
()));
}
private
void
assertNotNull
(
String
v1
)
{
if
(
v1
==
null
)
{
throw
new
ArithmeticException
(
"Operand may not be null"
);
}
}
private
void
assertNotNull
(
List
<
String
>
v1
)
{
if
(
v1
==
null
)
{
throw
new
ArithmeticException
(
"Operand may not be null"
);
}
}
private
void
assertNotNull
(
BigDecimal
v1
)
{
if
(
v1
==
null
)
{
throw
new
ArithmeticException
(
"Operand may not be null"
);
}
}
private
void
assertNotNull
(
BigDecimal
v1
,
BigDecimal
v2
)
{
if
(
v1
==
null
)
{
throw
new
ArithmeticException
(
"First operand may not be null"
);
}
if
(
v2
==
null
)
{
throw
new
ArithmeticException
(
"Second operand may not be null"
);
}
}
private
void
assertNotNull
(
String
v1
,
String
v2
)
{
if
(
v1
==
null
)
{
throw
new
ArithmeticException
(
"First operand may not be null"
);
}
if
(
v2
==
null
)
{
throw
new
ArithmeticException
(
"Second operand may not be null"
);
}
}
/**
* Is the string a number?
*
* @param st The string.
* @return <code>true</code>, if the input string is a number.
*/
private
boolean
isNumber
(
String
st
)
{
if
(
st
.
charAt
(
0
)
==
minusSign
&&
st
.
length
()
==
1
)
{
return
false
;
}
if
(
st
.
charAt
(
0
)
==
'+'
&&
st
.
length
()
==
1
)
{
return
false
;
}
if
(
st
.
charAt
(
0
)
==
decimalSeparator
&&
(
st
.
length
()
==
1
||
!
Character
.
isDigit
(
st
.
charAt
(
1
))))
{
return
false
;
}
if
(
st
.
charAt
(
0
)
==
'e'
||
st
.
charAt
(
0
)
==
'E'
)
{
return
false
;
}
for
(
char
ch
:
st
.
toCharArray
())
{
if
(!
Character
.
isDigit
(
ch
)
&&
ch
!=
minusSign
&&
ch
!=
decimalSeparator
&&
ch
!=
'e'
&&
ch
!=
'E'
&&
ch
!=
'+'
)
{
return
false
;
}
}
return
true
;
}
/**
* Implementation of the <i>Shunting Yard</i> algorithm to transform an infix expression to a RPN
* expression.
*
* @param expression The input expression in infx.
* @return A RPN representation of the expression, with each token as a list member.
*/
private
List
<
Token
>
shuntingYard
(
String
expression
)
{
List
<
Token
>
outputQueue
=
new
ArrayList
<
Token
>();
Stack
<
Token
>
stack
=
new
Stack
<
Token
>();
Tokenizer
tokenizer
=
new
Tokenizer
(
expression
);
Token
lastFunction
=
null
;
Token
previousToken
=
null
;
while
(
tokenizer
.
hasNext
())
{
Token
token
=
tokenizer
.
next
();
switch
(
token
.
type
)
{
case
STRINGPARAM:
stack
.
push
(
token
);
break
;
case
LITERAL:
case
HEX_LITERAL:
if
(
previousToken
!=
null
&&
(
previousToken
.
type
==
TokenType
.
LITERAL
||
previousToken
.
type
==
TokenType
.
HEX_LITERAL
))
{
throw
new
ExpressionException
(
"Missing operator at character position "
+
token
.
pos
);
}
outputQueue
.
add
(
token
);
break
;
case
VARIABLE:
outputQueue
.
add
(
token
);
break
;
case
FUNCTION:
stack
.
push
(
token
);
lastFunction
=
token
;
break
;
case
COMMA:
if
(
previousToken
!=
null
&&
previousToken
.
type
==
TokenType
.
OPERATOR
)
{
throw
new
ExpressionException
(
"Missing parameter(s) for operator "
+
previousToken
+
" at character position "
+
previousToken
.
pos
);
}
while
(!
stack
.
isEmpty
()
&&
stack
.
peek
().
type
!=
TokenType
.
OPEN_PAREN
)
{
outputQueue
.
add
(
stack
.
pop
());
}
if
(
stack
.
isEmpty
())
{
if
(
lastFunction
==
null
)
{
throw
new
ExpressionException
(
"Unexpected comma at character position "
+
token
.
pos
);
}
else
{
throw
new
ExpressionException
(
"Parse error for function '"
+
lastFunction
+
"' at character position "
+
token
.
pos
);
}
}
break
;
case
OPERATOR:
{
if
(
previousToken
!=
null
&&
(
previousToken
.
type
==
TokenType
.
COMMA
||
previousToken
.
type
==
TokenType
.
OPEN_PAREN
))
{
throw
new
ExpressionException
(
"Missing parameter(s) for operator "
+
token
+
" at character position "
+
token
.
pos
);
}
LazyOperator
o1
=
operators
.
get
(
token
.
surface
);
if
(
o1
==
null
)
{
throw
new
ExpressionException
(
"Unknown operator '"
+
token
+
"' at position "
+
(
token
.
pos
+
1
));
}
shuntOperators
(
outputQueue
,
stack
,
o1
);
stack
.
push
(
token
);
break
;
}
case
UNARY_OPERATOR:
{
if
(
previousToken
!=
null
&&
previousToken
.
type
!=
TokenType
.
OPERATOR
&&
previousToken
.
type
!=
TokenType
.
COMMA
&&
previousToken
.
type
!=
TokenType
.
OPEN_PAREN
&&
previousToken
.
type
!=
TokenType
.
UNARY_OPERATOR
)
{
throw
new
ExpressionException
(
"Invalid position for unary operator "
+
token
+
" at character position "
+
token
.
pos
);
}
LazyOperator
o1
=
operators
.
get
(
token
.
surface
);
if
(
o1
==
null
)
{
throw
new
ExpressionException
(
"Unknown unary operator '"
+
token
.
surface
.
substring
(
0
,
token
.
surface
.
length
()
-
1
)
+
"' at position "
+
(
token
.
pos
+
1
));
}
shuntOperators
(
outputQueue
,
stack
,
o1
);
stack
.
push
(
token
);
break
;
}
case
OPEN_PAREN:
if
(
previousToken
!=
null
)
{
if
(
previousToken
.
type
==
TokenType
.
LITERAL
||
previousToken
.
type
==
TokenType
.
CLOSE_PAREN
||
previousToken
.
type
==
TokenType
.
VARIABLE
||
previousToken
.
type
==
TokenType
.
HEX_LITERAL
)
{
// Implicit multiplication, e.g. 23(a+b) or (a+b)(a-b)
Token
multiplication
=
new
Token
();
multiplication
.
append
(
"*"
);
multiplication
.
type
=
TokenType
.
OPERATOR
;
stack
.
push
(
multiplication
);
}
// if the ( is preceded by a valid function, then it
// denotes the start of a parameter list
if
(
previousToken
.
type
==
TokenType
.
FUNCTION
)
{
outputQueue
.
add
(
token
);
}
}
stack
.
push
(
token
);
break
;
case
CLOSE_PAREN:
if
(
previousToken
!=
null
&&
previousToken
.
type
==
TokenType
.
OPERATOR
)
{
throw
new
ExpressionException
(
"Missing parameter(s) for operator "
+
previousToken
+
" at character position "
+
previousToken
.
pos
);
}
while
(!
stack
.
isEmpty
()
&&
stack
.
peek
().
type
!=
TokenType
.
OPEN_PAREN
)
{
outputQueue
.
add
(
stack
.
pop
());
}
if
(
stack
.
isEmpty
())
{
throw
new
ExpressionException
(
"Mismatched parentheses"
);
}
stack
.
pop
();
if
(!
stack
.
isEmpty
()
&&
stack
.
peek
().
type
==
TokenType
.
FUNCTION
)
{
outputQueue
.
add
(
stack
.
pop
());
}
}
previousToken
=
token
;
}
while
(!
stack
.
isEmpty
())
{
Token
element
=
stack
.
pop
();
if
(
element
.
type
==
TokenType
.
OPEN_PAREN
||
element
.
type
==
TokenType
.
CLOSE_PAREN
)
{
throw
new
ExpressionException
(
"Mismatched parentheses"
);
}
outputQueue
.
add
(
element
);
}
return
outputQueue
;
}
private
void
shuntOperators
(
List
<
Token
>
outputQueue
,
Stack
<
Token
>
stack
,
LazyOperator
o1
)
{
Expression
.
Token
nextToken
=
stack
.
isEmpty
()
?
null
:
stack
.
peek
();
while
(
nextToken
!=
null
&&
(
nextToken
.
type
==
Expression
.
TokenType
.
OPERATOR
||
nextToken
.
type
==
Expression
.
TokenType
.
UNARY_OPERATOR
)
&&
((
o1
.
isLeftAssoc
()
&&
o1
.
getPrecedence
()
<=
operators
.
get
(
nextToken
.
surface
)
.
getPrecedence
())
||
(
o1
.
getPrecedence
()
<
operators
.
get
(
nextToken
.
surface
).
getPrecedence
())))
{
outputQueue
.
add
(
stack
.
pop
());
nextToken
=
stack
.
isEmpty
()
?
null
:
stack
.
peek
();
}
}
/**
* Evaluates the expression.
*
* @return The result of the expression. Trailing zeros are stripped.
*/
public
BigDecimal
eval
()
{
return
eval
(
true
);
}
/**
* Evaluates the expression.
*
* @param stripTrailingZeros If set to <code>true</code> trailing zeros in the result are
* stripped.
* @return The result of the expression.
*/
public
BigDecimal
eval
(
boolean
stripTrailingZeros
)
{
Stack
<
LazyNumber
>
stack
=
new
Stack
<>();
for
(
final
Token
token
:
getRPN
())
{
switch
(
token
.
type
)
{
case
UNARY_OPERATOR:
{
final
LazyNumber
value
=
stack
.
pop
();
LazyNumber
result
=
()
->
operators
.
get
(
token
.
surface
).
eval
(
value
,
null
).
eval
();
stack
.
push
(
result
);
break
;
}
case
OPERATOR:
final
LazyNumber
v1
=
stack
.
pop
();
final
LazyNumber
v2
=
stack
.
pop
();
LazyNumber
result
=
()
->
operators
.
get
(
token
.
surface
).
eval
(
v2
,
v1
).
eval
();
stack
.
push
(
result
);
break
;
case
VARIABLE:
if
(!
variables
.
containsKey
(
token
.
surface
))
{
throw
new
ExpressionException
(
"Unknown operator or function: "
+
token
);
}
stack
.
push
(()
->
{
LazyNumber
lazyVariable
=
variables
.
get
(
token
.
surface
);
String
value
=
lazyVariable
==
null
?
null
:
lazyVariable
.
eval
();
return
value
==
null
?
null
:
new
BigDecimal
(
value
).
round
(
mc
).
toPlainString
();
});
break
;
case
FUNCTION:
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
LazyFunction
f
=
functions
.
get
(
token
.
surface
.
toUpperCase
(
Locale
.
ROOT
));
ArrayList
<
LazyNumber
>
p
=
new
ArrayList
<
LazyNumber
>(!
f
.
numParamsVaries
()
?
f
.
getNumParams
()
:
0
);
// pop parameters off the stack until we hit the start of
// this function's parameter list
while
(!
stack
.
isEmpty
()
&&
stack
.
peek
()
!=
PARAMS_START
)
{
p
.
add
(
0
,
stack
.
pop
());
}
if
(
stack
.
peek
()
==
PARAMS_START
)
{
stack
.
pop
();
}
LazyNumber
fResult
=
f
.
lazyEval
(
p
);
stack
.
push
(
fResult
);
break
;
case
OPEN_PAREN:
stack
.
push
(
PARAMS_START
);
break
;
case
LITERAL:
stack
.
push
(()
->
{
if
(
token
.
surface
.
equalsIgnoreCase
(
"NULL"
))
{
return
null
;
}
try
{
return
new
BigDecimal
(
token
.
surface
,
mc
).
toPlainString
();
}
catch
(
Exception
e1
)
{
return
token
.
surface
;
}
});
break
;
case
STRINGPARAM:
stack
.
push
(()
->
null
);
break
;
case
HEX_LITERAL:
stack
.
push
(()
->
new
BigDecimal
(
new
BigInteger
(
token
.
surface
.
substring
(
2
),
16
),
mc
).
toPlainString
());
break
;
default
:
throw
new
ExpressionException
(
"Unexpected token '"
+
token
.
surface
+
"' at character position "
+
token
.
pos
);
}
}
BigDecimal
result
=
new
BigDecimal
(
stack
.
pop
().
eval
());
return
result
==
null
?
null
:
stripTrailingZeros
?
result
.
stripTrailingZeros
()
:
result
;
}
/**
* Sets the precision for expression evaluation.
*
* @param precision The new precision.
* @return The expression, allows to chain methods.
*/
public
Expression
setPrecision
(
int
precision
)
{
this
.
mc
=
new
MathContext
(
precision
);
return
this
;
}
/**
* Sets the rounding mode for expression evaluation.
*
* @param roundingMode The new rounding mode.
* @return The expression, allows to chain methods.
*/
public
Expression
setRoundingMode
(
RoundingMode
roundingMode
)
{
this
.
mc
=
new
MathContext
(
mc
.
getPrecision
(),
roundingMode
);
return
this
;
}
/**
* Sets the characters other than letters and digits that are valid as the first character of a
* variable.
*
* @param chars The new set of variable characters.
* @return The expression, allows to chain methods.
*/
public
Expression
setFirstVariableCharacters
(
String
chars
)
{
this
.
firstVarChars
=
chars
;
return
this
;
}
/**
* Sets the characters other than letters and digits that are valid as the second and subsequent
* characters of a variable.
*
* @param chars The new set of variable characters.
* @return The expression, allows to chain methods.
*/
public
Expression
setVariableCharacters
(
String
chars
)
{
this
.
varChars
=
chars
;
return
this
;
}
/**
* Adds an operator to the list of supported operators.
*
* @param operator The operator to add.
* @return The previous operator with that name, or <code>null</code> if there was none.
*/
public
<
OPERATOR
extends
LazyOperator
>
OPERATOR
addOperator
(
OPERATOR
operator
)
{
String
key
=
operator
.
getOper
();
if
(
operator
instanceof
AbstractUnaryOperator
)
{
key
+=
"u"
;
}
return
(
OPERATOR
)
operators
.
put
(
key
,
operator
);
}
/**
* Adds a function to the list of supported functions
*
* @param function The function to add.
* @return The previous operator with that name, or <code>null</code> if there was none.
*/
public
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
Function
addFunction
(
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
Function
function
)
{
return
(
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
Function
)
functions
.
put
(
function
.
getName
(),
function
);
}
/**
* Adds a lazy function function to the list of supported functions
*
* @param function The function to add.
* @return The previous operator with that name, or <code>null</code> if there was none.
*/
public
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
LazyFunction
addLazyFunction
(
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
LazyFunction
function
)
{
return
functions
.
put
(
function
.
getName
(),
function
);
}
/**
* Sets a variable value.
*
* @param variable The variable name.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
setVariable
(
String
variable
,
BigDecimal
value
)
{
return
setVariable
(
variable
,
CreateLazyNumber
(
value
.
toPlainString
()));
}
/**
* Sets a variable value.
*
* @param variable The variable name.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
setVariable
(
String
variable
,
LazyNumber
value
)
{
variables
.
put
(
variable
,
value
);
return
this
;
}
/**
* Sets a variable value.
*
* @param variable The variable to set.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
setVariable
(
String
variable
,
String
value
)
{
if
(
isNumber
(
value
))
{
variables
.
put
(
variable
,
CreateLazyNumber
(
new
BigDecimal
(
value
,
mc
).
toPlainString
()));
}
else
if
(
value
.
equalsIgnoreCase
(
"null"
))
{
variables
.
put
(
variable
,
null
);
}
else
{
final
String
expStr
=
value
;
variables
.
put
(
variable
,
new
LazyNumber
()
{
private
final
Map
<
String
,
LazyNumber
>
outerVariables
=
variables
;
private
final
Map
<
String
,
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
LazyFunction
>
outerFunctions
=
functions
;
private
final
Map
<
String
,
LazyOperator
>
outerOperators
=
operators
;
private
final
String
innerExpressionString
=
expStr
;
private
final
MathContext
inneMc
=
mc
;
@Override
public
String
eval
()
{
Expression
innerE
=
new
Expression
(
innerExpressionString
,
inneMc
);
innerE
.
variables
=
outerVariables
;
innerE
.
functions
=
outerFunctions
;
innerE
.
operators
=
outerOperators
;
BigDecimal
val
=
innerE
.
eval
();
return
val
.
toPlainString
();
}
});
rpn
=
null
;
}
return
this
;
}
/**
* Creates a new inner expression for nested expression.
*
* @param expression The string expression.
* @return The inner Expression instance.
*/
private
Expression
createEmbeddedExpression
(
final
String
expression
)
{
final
Map
<
String
,
LazyNumber
>
outerVariables
=
variables
;
final
Map
<
String
,
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
LazyFunction
>
outerFunctions
=
functions
;
final
Map
<
String
,
LazyOperator
>
outerOperators
=
operators
;
final
MathContext
inneMc
=
mc
;
Expression
exp
=
new
Expression
(
expression
,
inneMc
);
exp
.
variables
=
outerVariables
;
exp
.
functions
=
outerFunctions
;
exp
.
operators
=
outerOperators
;
return
exp
;
}
/**
* Sets a variable value.
*
* @param variable The variable to set.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
with
(
String
variable
,
BigDecimal
value
)
{
return
setVariable
(
variable
,
value
);
}
/**
* Sets a variable value.
*
* @param variable The variable to set.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
with
(
String
variable
,
LazyNumber
value
)
{
return
setVariable
(
variable
,
value
);
}
/**
* Sets a variable value.
*
* @param variable The variable to set.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
and
(
String
variable
,
String
value
)
{
return
setVariable
(
variable
,
value
);
}
/**
* Sets a variable value.
*
* @param variable The variable to set.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
and
(
String
variable
,
BigDecimal
value
)
{
return
setVariable
(
variable
,
value
);
}
/**
* Sets a variable value.
*
* @param variable The variable to set.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
and
(
String
variable
,
LazyNumber
value
)
{
return
setVariable
(
variable
,
value
);
}
/**
* Sets a variable value.
*
* @param variable The variable to set.
* @param value The variable value.
* @return The expression, allows to chain methods.
*/
public
Expression
with
(
String
variable
,
String
value
)
{
return
setVariable
(
variable
,
value
);
}
/**
* Get an iterator for this expression, allows iterating over an expression token by token.
*
* @return A new iterator instance for this expression.
*/
public
Iterator
<
Token
>
getExpressionTokenizer
()
{
final
String
expression
=
this
.
expression
;
return
new
Tokenizer
(
expression
);
}
/**
* Cached access to the RPN notation of this expression, ensures only one calculation of the RPN
* per expression instance. If no cached instance exists, a new one will be created and put to the
* cache.
*
* @return The cached RPN instance.
*/
private
List
<
Token
>
getRPN
()
{
if
(
rpn
==
null
)
{
rpn
=
shuntingYard
(
this
.
expression
);
validate
(
rpn
);
}
return
rpn
;
}
/**
* Check that the expression has enough numbers and variables to fit the requirements of the
* operators and functions, also check for only 1 result stored at the end of the evaluation.
*/
private
void
validate
(
List
<
Token
>
rpn
)
{
/*-
* Thanks to Norman Ramsey:
* http://http://stackoverflow.com/questions/789847/postfix-notation-validation
*/
// each push on to this stack is a new function scope, with the value of
// each
// layer on the stack being the count of the number of parameters in
// that scope
Stack
<
Integer
>
stack
=
new
Stack
<
Integer
>();
// push the 'global' scope
stack
.
push
(
0
);
for
(
final
Token
token
:
rpn
)
{
switch
(
token
.
type
)
{
case
UNARY_OPERATOR:
if
(
stack
.
peek
()
<
1
)
{
throw
new
ExpressionException
(
"Missing parameter(s) for operator "
+
token
);
}
break
;
case
OPERATOR:
if
(
stack
.
peek
()
<
2
)
{
throw
new
ExpressionException
(
"Missing parameter(s) for operator "
+
token
);
}
// pop the operator's 2 parameters and add the result
stack
.
set
(
stack
.
size
()
-
1
,
stack
.
peek
()
-
2
+
1
);
break
;
case
FUNCTION:
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
.
LazyFunction
f
=
functions
.
get
(
token
.
surface
.
toUpperCase
(
Locale
.
ROOT
));
if
(
f
==
null
)
{
throw
new
ExpressionException
(
"Unknown function '"
+
token
+
"' at position "
+
(
token
.
pos
+
1
));
}
int
numParams
=
stack
.
pop
();
if
(!
f
.
numParamsVaries
()
&&
f
.
getNumParams
()
!=
0
&&
numParams
!=
f
.
getNumParams
())
{
throw
new
ExpressionException
(
"Function "
+
token
+
" expected "
+
f
.
getNumParams
()
+
" parameters, got "
+
numParams
);
}
if
(
stack
.
size
()
<=
0
)
{
throw
new
ExpressionException
(
"Too many function calls, maximum scope exceeded"
);
}
// push the result of the function
stack
.
set
(
stack
.
size
()
-
1
,
stack
.
peek
()
+
1
);
break
;
case
OPEN_PAREN:
stack
.
push
(
0
);
break
;
default
:
stack
.
set
(
stack
.
size
()
-
1
,
stack
.
peek
()
+
1
);
}
}
if
(
stack
.
size
()
>
1
)
{
throw
new
ExpressionException
(
"Too many unhandled function parameter lists"
);
}
else
if
(
stack
.
peek
()
>
1
)
{
throw
new
ExpressionException
(
"Too many numbers or variables"
);
}
else
if
(
stack
.
peek
()
<
1
)
{
throw
new
ExpressionException
(
"Empty expression"
);
}
}
/**
* Get a string representation of the RPN (Reverse Polish Notation) for this expression.
*
* @return A string with the RPN representation for this expression.
*/
public
String
toRPN
()
{
StringBuilder
result
=
new
StringBuilder
();
for
(
Token
t
:
getRPN
())
{
if
(
result
.
length
()
!=
0
)
{
result
.
append
(
" "
);
}
if
(
t
.
type
==
TokenType
.
VARIABLE
&&
variables
.
containsKey
(
t
.
surface
))
{
LazyNumber
innerVariable
=
variables
.
get
(
t
.
surface
);
String
innerExp
=
innerVariable
.
eval
();
if
(
isNumber
(
innerExp
))
{
// if it is a number, then we don't
// expan in the RPN
result
.
append
(
t
.
toString
());
}
else
{
// expand the nested variable to its RPN representation
Expression
exp
=
createEmbeddedExpression
(
innerExp
);
String
nestedExpRpn
=
exp
.
toRPN
();
result
.
append
(
nestedExpRpn
);
}
}
else
{
result
.
append
(
t
.
toString
());
}
}
return
result
.
toString
();
}
/**
* Exposing declared variables in the expression.
*
* @return All declared variables.
*/
public
Set
<
String
>
getDeclaredVariables
()
{
return
Collections
.
unmodifiableSet
(
variables
.
keySet
());
}
/**
* Exposing declared operators in the expression.
*
* @return All declared operators.
*/
public
Set
<
String
>
getDeclaredOperators
()
{
return
Collections
.
unmodifiableSet
(
operators
.
keySet
());
}
/**
* Exposing declared functions.
*
* @return All declared functions.
*/
public
Set
<
String
>
getDeclaredFunctions
()
{
return
Collections
.
unmodifiableSet
(
functions
.
keySet
());
}
/**
* @return The original expression string
*/
public
String
getExpression
()
{
return
expression
;
}
/**
* Returns a list of the variables in the expression.
*
* @return A list of the variable names in this expression.
*/
public
List
<
String
>
getUsedVariables
()
{
List
<
String
>
result
=
new
ArrayList
<
String
>();
Tokenizer
tokenizer
=
new
Tokenizer
(
expression
);
while
(
tokenizer
.
hasNext
())
{
Token
nextToken
=
tokenizer
.
next
();
String
token
=
nextToken
.
toString
();
if
(
nextToken
.
type
!=
TokenType
.
VARIABLE
||
token
.
equals
(
"PI"
)
||
token
.
equals
(
"e"
)
||
token
.
equals
(
"TRUE"
)
||
token
.
equals
(
"FALSE"
))
{
continue
;
}
result
.
add
(
token
);
}
return
result
;
}
/**
* The original expression used to construct this expression, without variables substituted.
*/
public
String
getOriginalExpression
()
{
return
this
.
originalExpression
;
}
/**
* {@inheritDoc}
*/
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
{
return
false
;
}
Expression
that
=
(
Expression
)
o
;
if
(
this
.
expression
==
null
)
{
return
that
.
expression
==
null
;
}
else
{
return
this
.
expression
.
equals
(
that
.
expression
);
}
}
/**
* {@inheritDoc}
*/
@Override
public
int
hashCode
()
{
return
this
.
expression
==
null
?
0
:
this
.
expression
.
hashCode
();
}
/**
* {@inheritDoc}
*/
@Override
public
String
toString
()
{
return
this
.
expression
;
}
/**
* Checks whether the expression is a boolean expression. An expression is considered a boolean
* expression, if the last operator or function is boolean. The IF function is handled special. If
* the third parameter is boolean, then the IF is also considered boolean, else non-boolean.
*
* @return <code>true</code> if the last operator/function was a boolean.
*/
public
boolean
isBoolean
()
{
List
<
Token
>
rpn
=
getRPN
();
if
(
rpn
.
size
()
>
0
)
{
for
(
int
i
=
rpn
.
size
()
-
1
;
i
>=
0
;
i
--)
{
Token
t
=
rpn
.
get
(
i
);
/*
* The IF function is handled special. If the third parameter is
* boolean, then the IF is also considered a boolean. Just skip
* the IF function to check the second parameter.
*/
if
(
t
.
surface
.
equals
(
"IF"
))
{
continue
;
}
if
(
t
.
type
==
TokenType
.
FUNCTION
)
{
return
functions
.
get
(
t
.
surface
).
isBooleanFunction
();
}
else
if
(
t
.
type
==
TokenType
.
OPERATOR
)
{
return
operators
.
get
(
t
.
surface
).
isBooleanOperator
();
}
}
}
return
false
;
}
public
List
<
String
>
infixNotation
()
{
final
List
<
String
>
infix
=
new
ArrayList
<
String
>();
Tokenizer
tokenizer
=
new
Tokenizer
(
expression
);
while
(
tokenizer
.
hasNext
())
{
Token
token
=
tokenizer
.
next
();
String
infixNotation
=
"{"
+
token
.
type
+
":"
+
token
.
surface
+
"}"
;
infix
.
add
(
infixNotation
);
}
return
infix
;
}
}
src/main/java/com/quantgroup/asset/distribution/util/calc/Function.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
import
java.math.BigDecimal
;
import
java.util.List
;
/**
* Base interface which is required for all directly evaluated functions.
*/
public
interface
Function
extends
LazyFunction
{
/**
* Implementation for this function.
*
* @param parameters Parameters will be passed by the expression evaluator as a {@link List} of
* {@link BigDecimal} values.
* @return The function must return a new {@link BigDecimal} value as a computing result.
*/
BigDecimal
eval
(
List
<
String
>
parameters
);
}
src/main/java/com/quantgroup/asset/distribution/util/calc/LazyFunction.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
import
java.util.List
;
/**
* Base interface which is required for lazily evaluated functions. A function is defined by a name,
* a number of parameters it accepts and of course the logic for evaluating the result.
*/
public
interface
LazyFunction
{
/**
* Gets the name of this function.<br>
* <br>
* The name is use to invoke this function in the expression.
*
* @return The name of this function.
*/
String
getName
();
/**
* Gets the number of parameters this function accepts.<br>
* <br>
* A value of <code>-1</code> denotes that this function accepts a variable number of parameters.
*
* @return The number of parameters this function accepts.
*/
int
getNumParams
();
/**
* Gets whether the number of accepted parameters varies.<br>
* <br>
* That means that the function does accept an undefined amount of parameters.
*
* @return <code>true</code> if the number of accepted parameters varies.
*/
boolean
numParamsVaries
();
/**
* Gets whether this function evaluates to a boolean expression.
*
* @return <code>true</code> if this function evaluates to a boolean
* expression.
*/
boolean
isBooleanFunction
();
/**
* Lazily evaluate this function.
*
* @param lazyParams The accepted parameters.
* @return The lazy result of this function.
*/
Expression
.
LazyNumber
lazyEval
(
List
<
Expression
.
LazyNumber
>
lazyParams
);
}
src/main/java/com/quantgroup/asset/distribution/util/calc/LazyOperator.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
/**
* Base interface which is required for all operators.
*/
public
interface
LazyOperator
{
/**
* Gets the String that is used to denote the operator in the expression.
*
* @return The String that is used to denote the operator in the expression.
*/
String
getOper
();
/**
* Gets the precedence value of this operator.
*
* @return the precedence value of this operator.
*/
int
getPrecedence
();
/**
* Gets whether this operator is left associative (<code>true</code>) or if this operator is right
* associative (<code>false</code>).
*
* @return <code>true</code> if this operator is left associative.
*/
boolean
isLeftAssoc
();
/**
* Gets whether this operator evaluates to a boolean expression.
*
* @return <code>true</code> if this operator evaluates to a boolean
* expression.
*/
boolean
isBooleanOperator
();
/**
* Implementation for this operator.
*
* @param v1 Operand 1.
* @param v2 Operand 2.
* @return The result of the operation.
*/
Expression
.
LazyNumber
eval
(
Expression
.
LazyNumber
v1
,
Expression
.
LazyNumber
v2
);
}
src/main/java/com/quantgroup/asset/distribution/util/calc/Operator.java
0 → 100644
View file @
89aebf3b
/*
* Copyright 2018 Udo Klimaschewski
*
* http://UdoJava.com/
* http://about.me/udo.klimaschewski
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package
com
.
quantgroup
.
asset
.
distribution
.
util
.
calc
;
import
java.math.BigDecimal
;
/**
* Base interface which is required for all operators.
*/
public
interface
Operator
extends
LazyOperator
{
/**
* Implementation for this operator.
*
* @param v1 Operand 1.
* @param v2 Operand 2.
* @return The result of the operation.
*/
BigDecimal
eval
(
String
v1
,
String
v2
);
}
src/test/java/com/quantgroup/asset/distribution/authority/AuthorityTest.java
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
authority
;
package
com
.
quantgroup
.
asset
.
distribution
.
authority
;
import
java.math.BigDecimal
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
@@ -7,8 +11,11 @@ import org.springframework.boot.test.context.SpringBootTest;
...
@@ -7,8 +11,11 @@ import org.springframework.boot.test.context.SpringBootTest;
import
org.springframework.test.context.junit4.SpringRunner
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
com.quantgroup.asset.distribution.AssetDistributionBootstrap
;
import
com.quantgroup.asset.distribution.AssetDistributionBootstrap
;
import
com.quantgroup.asset.distribution.exception.QGExceptionType
;
import
com.quantgroup.asset.distribution.exception.QGPreconditions
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AuthorityConfig
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAuthorityRepository
;
import
com.quantgroup.asset.distribution.service.jpa.repository.IAuthorityRepository
;
import
com.quantgroup.asset.distribution.util.calc.Expression
;
/**
/**
* 权限配置测试类
* 权限配置测试类
...
@@ -26,6 +33,31 @@ public class AuthorityTest {
...
@@ -26,6 +33,31 @@ public class AuthorityTest {
public
void
testAuthorityRepository
()
{
public
void
testAuthorityRepository
()
{
AuthorityConfig
config
=
authorityRepository
.
findByAuthKeyAndAuthPassAndEnableIsTrue
(
"lz_mo_fang"
,
"123456"
);
AuthorityConfig
config
=
authorityRepository
.
findByAuthKeyAndAuthPassAndEnableIsTrue
(
"lz_mo_fang"
,
"123456"
);
System
.
out
.
println
(
config
);
System
.
out
.
println
(
config
);
}
@Test
public
void
testRepository
()
{
}
public
static
void
main
(
String
[]
args
)
{
// com.quantgroup.asset.distribution.util.calc.Expression expression = new com.quantgroup.asset.distribution.util.calc.Expression("filter_fraud_point_v5==false");
// BigDecimal result = expression.with("filter_fraud_point_v5", "true").eval();
// System.out.println(result.compareTo(BigDecimal.ZERO) == 1);
// System.out.println(expression.with("filter_fraud_point_v5", "0.04").with("2022872_result", "32").eval());
// Expression expression = new Expression("filter_fraud_point_v5<0.4");
// System.out.println(expression.with("filter_fraud_point_v5", "0.03").eval());
String
expression
=
"filter_fraud_point_v5>0.06"
;
Map
<
String
,
Object
>
data
=
new
HashMap
<
String
,
Object
>();
data
.
put
(
"filter_fraud_point_v5"
,
(
Object
)
0.07
);
data
.
put
(
"v5"
,
(
Object
)
666
);
data
.
put
(
"liwenbin"
,
(
Object
)
7
);
Expression
ex
=
new
Expression
(
expression
);
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
data
.
entrySet
())
{
ex
.
with
(
entry
.
getKey
(),
String
.
valueOf
(
entry
.
getValue
()));
}
System
.
out
.
println
(
ex
.
eval
());
}
}
}
}
src/test/java/com/quantgroup/asset/distribution/distribute/DistributeTest.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
distribute
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.quantgroup.asset.distribution.AssetDistributionBootstrap
;
import
com.quantgroup.asset.distribution.model.entity.DistributeRecord
;
import
com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRecordService
;
import
com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRecord
;
@SpringBootTest
(
classes
=
AssetDistributionBootstrap
.
class
)
@RunWith
(
SpringRunner
.
class
)
public
class
DistributeTest
{
@Autowired
private
IAssetDistributeRecordService
assetDistributeRecordService
;
@Test
public
void
test
()
{
List
<
AssetDistributeRecord
>
assetDistributeRecords
=
assetDistributeRecordService
.
getDistributeRecord
(
"ASET0645dd8bdbe5458dacccad57ab22fbaf"
);
List
<
Integer
>
list
=
new
ArrayList
<>();
for
(
AssetDistributeRecord
assetDistributeRecord
:
assetDistributeRecords
)
{
JSONArray
array
=
JSON
.
parseObject
(
assetDistributeRecord
.
getAssetDistributeTravel
()).
getJSONArray
(
"records"
);
for
(
int
i
=
0
,
len
=
array
.
size
();
i
<
len
;
++
i
)
{
JSONObject
record
=
array
.
getJSONObject
(
i
);
list
.
add
(
record
.
getInteger
(
"type"
));
}
}
System
.
out
.
println
(
list
);
}
}
src/test/java/com/quantgroup/asset/distribution/rule/RuleValidTest.java
0 → 100644
View file @
89aebf3b
package
com
.
quantgroup
.
asset
.
distribution
.
rule
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
com.quantgroup.asset.distribution.AssetDistributionBootstrap
;
import
com.quantgroup.asset.distribution.service.rule.IRuleService
;
@SpringBootTest
(
classes
=
AssetDistributionBootstrap
.
class
)
@RunWith
(
SpringRunner
.
class
)
public
class
RuleValidTest
{
@Autowired
private
IRuleService
ruleService
;
@Test
public
void
testRuleValid
()
{
Map
<
String
,
Object
>
data
=
new
HashMap
<>();
data
.
put
(
"status"
,
"0"
);
System
.
out
.
println
(
ruleService
.
valid
(
"status!=0"
,
data
));
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment