Newer
Older
//@author Ajit Jagtap
//@version Mon Jul 09 2018 14:00:05 GMT+0530 (IST)
// Package servicebuildermdl will help you run BL and fetch data.
"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/utiliymdl/guidmdl"
"github.com/tidwall/sjson"
"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/constantmdl"
"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/validationmdl"
"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl"
"github.com/zhouzhuojie/conditions"
// GlobalConfigModel - GlobalConfigModel
type GlobalConfigModel struct {
Key string `json:"key"`
Value string `json:"value"`
Restrictions []string `json:"restrictions"`
}
var globalConfig map[string]GlobalConfigModel
var globalConfigMutex sync.Mutex
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// get server ip address
var (
serverIP = func() string {
ifaces, err := net.Interfaces()
if err != nil {
return ""
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
addrs, err := iface.Addrs()
if err != nil {
return ""
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
if ip = ip.To4(); ip == nil {
continue // not an ipv4 address
}
return ip.String()
}
}
return ""
}()
)
globalConfig = make(map[string]GlobalConfigModel)
globalConfigMutex = sync.Mutex{}
// DebugInfo - DebugInfo
type DebugInfo struct {
StackTrace strings.Builder `json:"stackTrace"`
PerformanceInfo strings.Builder `json:"performanceInfo"`
}
// LoadData is a method sign for loader methods
type LoadData = func(ab *AbstractBusinessLogicHolder) error
// FinalStepProcessOutput is a method sign for loader methods
type FinalStepProcessOutput = func(ab *AbstractBusinessLogicHolder) (*interface{}, error)
// AbstractBusinessLogicHolder use this type to inheritance
type AbstractBusinessLogicHolder struct {
localServiceData map[string]interface{}
pricipalObject Principal
globalConfigData map[string]GlobalConfigModel
GlobalErrorCode int
ServiceError interface{}
TransactionEnable bool
DatabaseType string // database type for transaction begin(MYSQL,SQLSERVER etc.)

Vikram Ingawale
committed
IgnoreStrictMode bool
TXN *sql.Tx // transaction for MySQL
SQLServerTXN *sql.Tx // Transaction for SQLServer
}
// SetGlobalConfig - SetGlobalConfig
func SetGlobalConfig(configs map[string]GlobalConfigModel) {
globalConfigMutex.Lock()
defer globalConfigMutex.Unlock()
once.Do(func() {
if configs != nil {
globalConfig = configs
}
})
}
// GetDataString will give you string
func (ab *AbstractBusinessLogicHolder) GetDataString(key string) (string, bool) {
//check in map
temp, found := ab.localServiceData[key]
if errormdl.CheckBool(!found) {
return "", false
}
// cast it
value, ok := temp.(string)
if errormdl.CheckBool1(!ok) {
return "", false
}
return value, true
}
// GetDataInt will give you int
func (ab *AbstractBusinessLogicHolder) GetDataInt(key string) (int64, bool) {
temp, found := ab.localServiceData[key]
if errormdl.CheckBool(!found) {
return 0, false
}
// cast it
if errormdl.CheckBool1(!ok) {
return 0, false
}
return value, true
}
// GetDataInterface will give you int
func (ab *AbstractBusinessLogicHolder) GetDataInterface(key string) (interface{}, bool) {
//check in map
temp, found := ab.localServiceData[key]
if errormdl.CheckBool(!found) {
return nil, false
}
return temp, true
}
// GetDataResultset will give you int
func (ab *AbstractBusinessLogicHolder) GetDataResultset(key string) (*gjson.Result, bool) {
temp, found := ab.localServiceData[key]
if errormdl.CheckBool(!found) {
loggermdl.LogWarn("Key not found -", key)
return &gjson.Result{}, false
}
// cast it
value, ok := temp.(*gjson.Result)
if errormdl.CheckBool1(!ok) {
return &gjson.Result{}, false
}
return value, true
}
// GetMQLRequestData - returns MQLRequestData
func (ab *AbstractBusinessLogicHolder) GetMQLRequestData() (*gjson.Result, bool) {
//check in map
temp, found := ab.localServiceData[constantmdl.MQLRequestData]
if errormdl.CheckBool(!found) {
loggermdl.LogWarn("MQL Request Data not Found")
return &gjson.Result{}, false
}
// cast it
value, ok := temp.(*gjson.Result)
if errormdl.CheckBool1(!ok) {
return &gjson.Result{}, false
}
return value, true
}
// GetDataBool will give you int
func (ab *AbstractBusinessLogicHolder) GetDataBool(key string) (bool, bool) {
temp, found := ab.localServiceData[key]
if errormdl.CheckBool(!found) {
return false, false
}
// cast it
value, ok := temp.(bool)
if errormdl.CheckBool1(!ok) {
return false, false
}
return value, true
}
// GetCustomData will give you string
func (ab *AbstractBusinessLogicHolder) GetCustomData(key string) (interface{}, bool) {
temp, found := ab.localServiceData[key]
if errormdl.CheckBool(!found) {
return 0, false
}
// cast it
return temp, true
}
// GetGlobalConfigString - return string value for global config key
func (ab *AbstractBusinessLogicHolder) GetGlobalConfigString(key string) (string, bool) {
globalConfigMutex.Lock()
defer globalConfigMutex.Unlock()
value, found := ab.globalConfigData[key]
if errormdl.CheckBool(!found) {
return "", false
}
}).Any() {
return value.Value, true
}
if (linq.From(value.Restrictions).WhereT(func(str string) bool {
return str == "Restricted" || str == "RESTRICTED"
}).Any()) && ab.pricipalObject.UserID != "" {
for i := 0; i < len(value.Restrictions); i++ {
for j := 0; j < len(ab.pricipalObject.Groups); j++ {
if ab.pricipalObject.Groups[j] == value.Restrictions[i] {
return value.Value, true
}
}
}
return "", false
}
return value.Value, true
func (ab *AbstractBusinessLogicHolder) New(principalObject *Principal) *AbstractBusinessLogicHolder {
ab.localServiceData = make(map[string]interface{})
ab.globalConfigData = globalConfig
ab.pricipalObject = *principalObject
// SetResultset will return map data with finaldata key
func (ab *AbstractBusinessLogicHolder) SetResultset(key string, obj *gjson.Result) {
ab.localServiceData[key] = obj
}
// SetMQLRequestData - set value
func (ab *AbstractBusinessLogicHolder) SetMQLRequestData(obj *gjson.Result) {
ab.localServiceData[constantmdl.MQLRequestData] = obj
}
// SetByteData will set byte data as gjson.Result
func (ab *AbstractBusinessLogicHolder) SetByteData(key string, obj []byte) {
rs := gjson.ParseBytes(obj)
ab.localServiceData[key] = &rs
// SetMQLToken will set token in header
func (ab *AbstractBusinessLogicHolder) SetMQLToken(token string) {
ab.localServiceData["MQLToken"] = token
}
// SetCustomData set custom user data in map
func (ab *AbstractBusinessLogicHolder) SetCustomData(key string, data interface{}) {
ab.localServiceData[key] = data
// SetErrorData will set error
func (ab *AbstractBusinessLogicHolder) SetErrorData(data interface{}) {
ab.ServiceError = data
}
// GetFinalData will return map data with finaldata key
func (ab *AbstractBusinessLogicHolder) GetFinalData() *interface{} {
a := ab.localServiceData["finaldata"]
// SetFinalData will return map data with finaldata key
func (ab *AbstractBusinessLogicHolder) SetFinalData(data interface{}) {
ab.localServiceData["finaldata"] = data
// GetClientIP will returns client ip address
func (ab *AbstractBusinessLogicHolder) GetClientIP() string {
return ab.pricipalObject.ClientIP
}
// GetServerIP will returns server ip address
func (ab *AbstractBusinessLogicHolder) GetServerIP() string {
return serverIP
}
// SetErrorCode - SetErrorCode in service context
func (ab *AbstractBusinessLogicHolder) SetErrorCode(code int) {
ab.GlobalErrorCode = code
}
// GetErrorData - GetErrorData in service context
func (ab *AbstractBusinessLogicHolder) GetErrorData() interface{} {
if ab == nil {
return nil
}
return ab.ServiceError
}
// GetErrorCode - GetErrorCode in service context
func (ab *AbstractBusinessLogicHolder) GetErrorCode() int {
func (ab *AbstractBusinessLogicHolder) EchoBL() (map[string]interface{}, error) {
return map[string]interface{}{
"ok": int64(1),
}
// Step help to maintain steps
type Step struct {
Stepname string
expr conditions.Expr
processDataFunc LoadData
IsValidator bool
ValidationDataKey string
ValidationFunc func(interface{}) error
RunFunc func() (map[string]interface{}, error)
ErrorFunc func() (map[string]interface{}, error)
}
// ServiceBuilder will help you to run steps
type ServiceBuilder struct {
ServiceName string
steps []Step
businessLogicHolder *AbstractBusinessLogicHolder
}
// GetSB Gives you service builder from where you can run steps
func GetSB(name string, ab *AbstractBusinessLogicHolder) *ServiceBuilder {
newsb := ServiceBuilder{}
newsb.ServiceName = name
newsb.businessLogicHolder = ab
return &newsb
}
// AddStep will add func step with rule
// Stepname : Give Name to step. It will appear in log.
// Rule : Give Ybl rule
// blfunc : Give Business Logic function pointer
// errorfunc : Give Error function pointer
func (sb *ServiceBuilder) AddStep(stepname, rule string, ld LoadData, blfunc, errorfunc func() (map[string]interface{}, error)) *ServiceBuilder {
if errormdl.CheckErr(sb.ServiceError) != nil {
loggermdl.LogError(sb.ServiceError)
return sb
}
step.expr = cachedRule
} else {
// Parse the condition language and get expression
p := conditions.NewParser(strings.NewReader(rule))
expr, err := p.Parse()
if errormdl.CheckErr1(err) != nil {
loggermdl.LogError("Error in step: ", stepname, err)
sb.ServiceError = errormdl.CheckErr1(err)
step.RunFunc = blfunc
step.ErrorFunc = errorfunc
step.Stepname = stepname
step.processDataFunc = ld
sb.steps = append(sb.steps, step)
return sb
}
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
// AddStepWithGoTo - AddStep with goto pointer
func (sb *ServiceBuilder) AddStepWithGoTo(stepname, rule string, ld LoadData, blfunc, errorfunc func() (map[string]interface{}, error), gotoStepName string) *ServiceBuilder {
if errormdl.CheckErr(sb.ServiceError) != nil {
loggermdl.LogError(sb.ServiceError)
return sb
}
step := Step{}
//Check rule in cache
mutex.Lock()
cachedRule, found := ruleCache[rule]
mutex.Unlock()
if errormdl.CheckBool(found) {
step.expr = cachedRule
} else {
// Parse the condition language and get expression
p := conditions.NewParser(strings.NewReader(rule))
expr, err := p.Parse()
if errormdl.CheckErr1(err) != nil {
loggermdl.LogError("Error in step: ", stepname, err)
sb.ServiceError = errormdl.CheckErr1(err)
return sb
}
step.expr = expr
mutex.Lock()
ruleCache[rule] = expr
mutex.Unlock()
}
step.RunFunc = blfunc
step.ErrorFunc = errorfunc
step.Stepname = stepname
step.processDataFunc = ld
step.JumpStep = gotoStepName
sb.steps = append(sb.steps, step)
return sb
}
// AddValidation add validation step for give dataKey
func (sb *ServiceBuilder) AddValidation(dataKey string, validationfunc func(interface{}) error) *ServiceBuilder {
if errormdl.CheckErr(sb.ServiceError) != nil {
loggermdl.LogError(sb.ServiceError)
return sb
}
step := Step{}
step.IsValidator = true
step.ValidationDataKey = dataKey
step.ValidationFunc = validationfunc
step.Stepname = "Validation Step"
sb.steps = append(sb.steps, step)
return sb
}
func (sb *ServiceBuilder) findStepIndex(stepName string) (int, bool) {
for i, step := range sb.steps {
if step.Stepname == stepName {
return i, true
}
}
return 0, false
}
func (sb *ServiceBuilder) Run(fn FinalStepProcessOutput) (*interface{}, error) {
if errormdl.CheckErr(sb.ServiceError) != nil {
loggermdl.LogError(sb.ServiceError)
return nil, errormdl.CheckErr(sb.ServiceError)
}
_, ok := sb.businessLogicHolder.localServiceData["finaldata"]
if ok {
return sb.businessLogicHolder.GetFinalData(), nil
}
for i := 0; i < len(sb.steps); i++ {
if maxStepCount == 0 {
loggermdl.LogError("Your steps are in recursion and cross limit of 100 steps")
return nil, errormdl.Wrap("Your steps are in recursion and cross limit of 100 steps")
if sb.steps[i].IsValidator {
validationError := sb.executeValidationFunction(sb.steps[i].ValidationDataKey, sb.steps[i].ValidationFunc)
if errormdl.CheckErr(validationError) != nil {
return nil, errormdl.CheckErr(validationError)
}
continue
}
if sb.steps[i].processDataFunc != nil {
daoError := sb.steps[i].processDataFunc(sb.businessLogicHolder)
if errormdl.CheckErr1(daoError) != nil {
loggermdl.LogError(daoError)
tmp, blError := sb.steps[i].RunFunc()
if errormdl.CheckErr2(blError) != nil {
loggermdl.LogError(blError)
return nil, errormdl.CheckErr2(blError)
}
// Validation using conditions
result, evaluteError := conditions.Evaluate(sb.steps[i].expr, tmp)
if errormdl.CheckErr3(evaluteError) != nil {
loggermdl.LogError(evaluteError)
return nil, errormdl.CheckErr3(evaluteError)
}
// if validation fails
// loggermdl.LogWarn(sb.steps[i].Stepname, "Failed", result)
// jump step is a functionality like go to on particular step
if sb.steps[i].JumpStep != "" {
_, recoveryError := sb.executeErrorFunction(sb.steps[i].ErrorFunc)
if errormdl.CheckErr(recoveryError) != nil {
loggermdl.LogError(recoveryError)
return nil, errormdl.CheckErr(recoveryError)
}
index, ok := sb.findStepIndex(sb.steps[i].JumpStep)
if !ok {
loggermdl.LogError("Step Name spcify in GOTO not found: " + sb.steps[i].JumpStep)
return nil, errormdl.Wrap("Step Name spcify in GOTO not found: " + sb.steps[i].JumpStep)
}
i = index - 1
continue
return sb.executeErrorFunction(sb.steps[i].ErrorFunc)
return sb.finalOutput(fn)
}
// executeValidationFunction exceute when validation failed for any step
func (sb *ServiceBuilder) executeValidationFunction(dataKey string, fn func(interface{}) error) error {
validationData, ok := sb.businessLogicHolder.localServiceData[dataKey]
if !ok {
loggermdl.LogError("Data Not Found For Validation: " + dataKey)
return errormdl.Wrap("Data Not Found For Validation: " + dataKey)
}
if fn == nil {
return validationmdl.ValidateStruct(validationData)
}
return fn(validationData)
}
// executeErrorFunction exceute when validation failed for any step
func (sb *ServiceBuilder) executeErrorFunction(fn func() (map[string]interface{}, error)) (*interface{}, error) {
loggermdl.LogError("Data Validation failed and No recovery function found")
return nil, errormdl.Wrap("Data Validation failed and No recovery function found")
_, err := fn()
if errormdl.CheckErr(err) != nil {
loggermdl.LogError(err)
return nil, errormdl.CheckErr(err)
}
return sb.businessLogicHolder.GetFinalData(), nil
// finalOutput return Final output
func (sb *ServiceBuilder) finalOutput(fn FinalStepProcessOutput) (*interface{}, error) {
return sb.businessLogicHolder.GetFinalData(), nil
}
return fn(sb.businessLogicHolder)
}
// Principal - Object inside JWT token
type Principal struct {
UserID string `json:"userId"`
Groups []string `json:"groups"`
SessionExpiration time.Time `json:"sessionExpiration"`
HitsCount int `json:"hitsCount"`
}
// // SetPrincipalObject - Set Principal object to BLHolder
// func (ab *AbstractBusinessLogicHolder) SetPrincipalObject(object *Principal) {
// ab.pricipalObject = *object
// }
// GetPrincipalObject - return Principal object from BLHolder
func (ab *AbstractBusinessLogicHolder) GetPrincipalObject() *Principal {
return &ab.pricipalObject
}
// APIResponse - APIResponse
type APIResponse struct {
StatusCode int
Body []byte
Headers []Header
}
type Header struct {
Key string
Value []string
}
// GetResposeObject - return Response object from BLHolder
func (ab *AbstractBusinessLogicHolder) GetResposeObject(responseKey string) (*APIResponse, error) {
tmp, ok := ab.localServiceData[responseKey]
if !ok {
return &APIResponse{}, errormdl.Wrap("Response not found for key: " + responseKey)
}
value, ok := tmp.(APIResponse)
if !ok {
return &APIResponse{}, errormdl.Wrap("Data inside memory is not of type APIResponse: " + responseKey)
}
return &value, nil
}
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
// FetchValues -FetchValues
func (ab *AbstractBusinessLogicHolder) FetchValues(keyName, query string) (gjson.Result, int, error) {
var result gjson.Result
if keyName == "Principal" {
if query == "userId" {
result = gjson.Parse(`{"loginId":"` + ab.GetPrincipalObject().UserID + `"}`).Get("loginId")
}
if query == "groups" {
var err error
groupData := ""
for _, group := range ab.GetPrincipalObject().Groups {
groupData, err = sjson.Set(groupData, "-1", group)
if err != nil {
loggermdl.LogError(err)
return result, errormdl.SJSONERROR, err
}
}
result = gjson.Parse(groupData)
}
if query == "clientIP" {
result = gjson.Parse(`{"clientIP":"` + ab.GetPrincipalObject().ClientIP + `"}`).Get("clientIP")
}
if query == "token" {
result = gjson.Parse(`{"token":"` + ab.GetPrincipalObject().Token + `"}`).Get("token")
}
if strings.Contains(query, "metadata") {
if strings.Contains(query, ":") {
token := strings.Split(query, ":")
if len(token) > 0 {
result = gjson.Parse(ab.GetPrincipalObject().Metadata).Get(token[1])
}
} else {
result = gjson.Parse(ab.GetPrincipalObject().Metadata)
}
}
return result, errormdl.NOERROR, nil
}
if keyName == "GlobalConfig" {
result, ok := ab.GetGlobalConfigString(query)
if !ok {
loggermdl.LogError("Key Not Found in global config: " + query)
return gjson.Parse(result), errormdl.KEYNOTFOUND, errormdl.Wrap("Key Not Found in global config: " + query)
}
loggermdl.LogInfo(result)
return gjson.Parse(`{"config":"` + result + `"}`).Get("config"), errormdl.NOERROR, nil
}
if keyName == "~tokenUserId" {
return gjson.Parse(`{"loginId":"` + ab.GetPrincipalObject().UserID + `"}`).Get("loginId"), errormdl.NOERROR, nil
}
if keyName == "~TIME" {
TIME, err := sjson.Set("{}", "time", time.Now().Unix())
if errormdl.CheckErr(err) != nil {
loggermdl.LogError(err)
return result, errormdl.SJSONERROR, errormdl.CheckErr(err)
}
return gjson.Parse(TIME).Get("time"), errormdl.NOERROR, nil
}
if keyName == "~GUID" {
return gjson.Parse(`{"guid":"` + guidmdl.GetGUID() + `"}`).Get("guid"), errormdl.NOERROR, nil
}
if keyName == "EMPTYJSON" {
return gjson.Parse("{}"), errormdl.NOERROR, nil
}
rs, ok := ab.GetDataResultset(keyName)
if !ok {
loggermdl.LogError("Key Not Found: " + keyName)
return result, errormdl.KEYNOTFOUND, errormdl.Wrap("Key Not Found: " + keyName)
}
if query != "*" {
result = rs.Get(query)
} else {
result = *rs
}
return result, errormdl.NOERROR, nil
}
// GetAllAbsData - GetAllAbsData
func (ab *AbstractBusinessLogicHolder) GetAbLocalServiceData() map[string]interface{} {
return ab.localServiceData
}