/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package parser import ( "github.com/pkg/errors" "github.com/seata/seata-go/pkg/saga/statemachine/statelang" "strconv" "strings" "sync" ) type StateMachineParser interface { GetType() string Parse(content string) (statelang.StateMachine, error) } type StateParser interface { StateType() string Parse(stateName string, stateMap map[string]interface{}) (statelang.State, error) } type BaseStateParser struct { } func NewBaseStateParser() *BaseStateParser { return &BaseStateParser{} } func (b BaseStateParser) ParseBaseAttributes(stateName string, state statelang.State, stateMap map[string]interface{}) error { state.SetName(stateName) comment, err := b.GetStringOrDefault(stateName, stateMap, "Comment", "") if err != nil { return err } state.SetComment(comment) next, err := b.GetStringOrDefault(stateName, stateMap, "Next", "") if err != nil { return err } state.SetNext(next) return nil } func (b BaseStateParser) GetString(stateName string, stateMap map[string]interface{}, key string) (string, error) { value := stateMap[key] if value == nil { var result string return result, errors.New("State [" + stateName + "] " + key + " not exist") } valueAsString, ok := value.(string) if !ok { var s string return s, errors.New("State [" + stateName + "] " + key + " illegal, required string") } return valueAsString, nil } func (b BaseStateParser) GetStringOrDefault(stateName string, stateMap map[string]interface{}, key string, defaultValue string) (string, error) { value := stateMap[key] if value == nil { return defaultValue, nil } valueAsString, ok := value.(string) if !ok { return defaultValue, errors.New("State [" + stateName + "] " + key + " illegal, required string") } return valueAsString, nil } func (b BaseStateParser) GetSlice(stateName string, stateMap map[string]interface{}, key string) ([]interface{}, error) { value := stateMap[key] if value == nil { var result []interface{} return result, errors.New("State [" + stateName + "] " + key + " not exist") } valueAsSlice, ok := value.([]interface{}) if !ok { var slice []interface{} return slice, errors.New("State [" + stateName + "] " + key + " illegal, required []interface{}") } return valueAsSlice, nil } func (b BaseStateParser) GetSliceOrDefault(stateName string, stateMap map[string]interface{}, key string, defaultValue []interface{}) ([]interface{}, error) { value := stateMap[key] if value == nil { return defaultValue, nil } valueAsSlice, ok := value.([]interface{}) if !ok { return defaultValue, errors.New("State [" + stateName + "] " + key + " illegal, required []interface{}") } return valueAsSlice, nil } func (b BaseStateParser) GetMapOrDefault(stateMap map[string]interface{}, key string, defaultValue map[string]interface{}) (map[string]interface{}, error) { value := stateMap[key] if value == nil { return defaultValue, nil } valueAsMap, ok := value.(map[string]interface{}) if !ok { return defaultValue, nil } return valueAsMap, nil } func (b BaseStateParser) GetBool(stateName string, stateMap map[string]interface{}, key string) (bool, error) { value := stateMap[key] if value == nil { return false, errors.New("State [" + stateName + "] " + key + " not exist") } valueAsBool, ok := value.(bool) if !ok { return false, errors.New("State [" + stateName + "] " + key + " illegal, required bool") } return valueAsBool, nil } func (b BaseStateParser) GetBoolOrDefault(stateName string, stateMap map[string]interface{}, key string, defaultValue bool) (bool, error) { value := stateMap[key] if value == nil { return defaultValue, nil } valueAsBool, ok := value.(bool) if !ok { return defaultValue, errors.New("State [" + stateName + "] " + key + " illegal, required bool") } return valueAsBool, nil } func (b BaseStateParser) GetIntOrDefault(stateName string, stateMap map[string]interface{}, key string, defaultValue int) (int, error) { value := stateMap[key] if value == nil { return defaultValue, nil } // use float64 conversion when the configuration file is json, and use int conversion when the configuration file is yaml valueAsFloat64, okToFloat64 := value.(float64) valueAsInt, okToInt := value.(int) if !okToFloat64 && !okToInt { return defaultValue, errors.New("State [" + stateName + "] " + key + " illegal, required int") } if okToFloat64 { floatStr := strconv.FormatFloat(valueAsFloat64, 'f', -1, 64) if strings.Contains(floatStr, ".") { return defaultValue, errors.New("State [" + stateName + "] " + key + " illegal, required int") } return int(valueAsFloat64), nil } return valueAsInt, nil } func (b BaseStateParser) GetFloat64OrDefault(stateName string, stateMap map[string]interface{}, key string, defaultValue float64) (float64, error) { value := stateMap[key] if value == nil { return defaultValue, nil } // use float64 conversion when the configuration file is json, and use int conversion when the configuration file is yaml valueAsFloat64, okToFloat64 := value.(float64) valueAsInt, okToInt := value.(int) if !okToFloat64 && !okToInt { return defaultValue, errors.New("State [" + stateName + "] " + key + " illegal, required float64") } if okToFloat64 { return valueAsFloat64, nil } return float64(valueAsInt), nil } type StateParserFactory interface { RegistryStateParser(stateType string, stateParser StateParser) GetStateParser(stateType string) StateParser } type DefaultStateParserFactory struct { stateParserMap map[string]StateParser mutex sync.Mutex } func NewDefaultStateParserFactory() *DefaultStateParserFactory { var stateParserMap map[string]StateParser = make(map[string]StateParser) return &DefaultStateParserFactory{ stateParserMap: stateParserMap, } } // InitDefaultStateParser init StateParser by default func (d *DefaultStateParserFactory) InitDefaultStateParser() { choiceStateParser := NewChoiceStateParser() serviceTaskStateParser := NewServiceTaskStateParser() subStateMachineParser := NewSubStateMachineParser() succeedEndStateParser := NewSucceedEndStateParser() compensationTriggerStateParser := NewCompensationTriggerStateParser() failEndStateParser := NewFailEndStateParser() scriptTaskStateParser := NewScriptTaskStateParser() d.RegistryStateParser(choiceStateParser.StateType(), choiceStateParser) d.RegistryStateParser(serviceTaskStateParser.StateType(), serviceTaskStateParser) d.RegistryStateParser(subStateMachineParser.StateType(), subStateMachineParser) d.RegistryStateParser(succeedEndStateParser.StateType(), succeedEndStateParser) d.RegistryStateParser(compensationTriggerStateParser.StateType(), compensationTriggerStateParser) d.RegistryStateParser(compensationTriggerStateParser.StateType(), compensationTriggerStateParser) d.RegistryStateParser(failEndStateParser.StateType(), failEndStateParser) d.RegistryStateParser(scriptTaskStateParser.StateType(), scriptTaskStateParser) } func (d *DefaultStateParserFactory) RegistryStateParser(stateType string, stateParser StateParser) { d.mutex.Lock() defer d.mutex.Unlock() d.stateParserMap[stateType] = stateParser } func (d *DefaultStateParserFactory) GetStateParser(stateType string) StateParser { return d.stateParserMap[stateType] }