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
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

Vikram Ingawale
committed
IgnoreStrictMode bool
}
// 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
}
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
// SetMQLToken will set token in header
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
// 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
}
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
// 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
}
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
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
// 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
}