github.com/TIBCOSoftware/flogo-lib@v0.5.9/core/data/resolve.go (about) 1 package data 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 "github.com/TIBCOSoftware/flogo-lib/logger" 9 ) 10 11 type Resolver interface { 12 Resolve(toResolve string, scope Scope) (value interface{}, err error) 13 } 14 15 var resolver = &BasicResolver{} 16 17 func GetBasicResolver() Resolver { 18 return resolver 19 } 20 21 type BasicResolver struct { 22 } 23 24 func (r *BasicResolver) Resolve(toResolve string, scope Scope) (value interface{}, err error) { 25 26 var details *ResolutionDetails 27 28 if strings.HasPrefix(toResolve, "${") { 29 details, err = GetResolutionDetailsOld(toResolve) 30 } else if strings.HasPrefix(toResolve, "$") { 31 details, err = GetResolutionDetails(toResolve[1:]) 32 } else { 33 34 if scope == nil { 35 //todo is this what we should do in this circumstance? or throw an error? 36 return toResolve, nil 37 } 38 39 return SimpleScopeResolve(toResolve, scope) 40 } 41 42 if err != nil { 43 return nil, err 44 } 45 46 if details == nil { 47 return nil, fmt.Errorf("unable to resolve '%s'", toResolve) 48 } 49 50 var exists bool 51 52 switch details.ResolverName { 53 case "property": 54 // Property resolution 55 provider := GetPropertyProvider() 56 value, exists = provider.GetProperty(details.Property + details.Path) //should we add the path and reset it to "" 57 if !exists { 58 err := fmt.Errorf("failed to resolve Property: '%s', ensure that property is configured in the application", details.Property) 59 logger.Error(err.Error()) 60 return nil, err 61 } 62 case "env": 63 // Environment resolution 64 value, exists = os.LookupEnv(details.Property + details.Path) 65 if !exists { 66 err := fmt.Errorf("failed to resolve Environment Variable: '%s', ensure that variable is configured", details.Property) 67 logger.Error(err.Error()) 68 return "", err 69 } 70 case ".": 71 //Current scope resolution 72 attr, exists := scope.GetAttr(details.Property) 73 if !exists { 74 return nil, fmt.Errorf("failed to resolve current scope: '%s', not found in scope", details.Property) 75 } 76 value = attr.Value() 77 default: 78 return nil, fmt.Errorf("unsupported resolver: %s", details.ResolverName) 79 } 80 81 value = GetComplexValue(value) 82 if details.Path != "" { 83 value, err = PathGetValue(value, details.Path) 84 if err != nil { 85 logger.Error(err.Error()) 86 return nil, err 87 } 88 } 89 90 return value, nil 91 } 92 93 func SimpleScopeResolve(toResolve string, scope Scope) (value interface{}, err error) { 94 //idx := strings.Index(toResolve, ".") 95 idx := strings.IndexFunc(toResolve, isSep) 96 97 if idx != -1 { 98 attr, found := scope.GetAttr(toResolve[:idx]) 99 if !found { 100 return nil, fmt.Errorf("could not resolve '%s'", toResolve) 101 } 102 value, err := PathGetValue(attr.Value(), toResolve[idx:]) 103 if err != nil { 104 logger.Error(err.Error()) 105 return nil, err 106 } 107 return value, nil 108 109 } else { 110 attr, found := scope.GetAttr(toResolve) 111 if !found { 112 return nil, fmt.Errorf("could not resolve '%s'", toResolve) 113 } 114 115 return attr.Value(), nil 116 } 117 } 118 119 type ResolutionDetails struct { 120 ResolverName string 121 Item string 122 Property string 123 Path string 124 } 125 126 func GetResolutionDetails(toResolve string) (*ResolutionDetails, error) { 127 128 //todo optimize, maybe tokenize first 129 details := &ResolutionDetails{} 130 131 bracketIdx := strings.Index(toResolve, "]") 132 exprLen := len(toResolve) 133 if bracketIdx == (exprLen-1) && (strings.HasPrefix(toResolve, "property") || strings.HasPrefix(toResolve, "env")) { 134 //$property[] or $env[] resolution 135 itemIdx := strings.Index(toResolve, "[") 136 details.ResolverName = toResolve[:itemIdx] 137 details.Property = toResolve[itemIdx+1 : exprLen-1] 138 return details, nil 139 } 140 141 dotIdx := strings.Index(toResolve, ".") 142 if dotIdx == -1 { 143 return nil, fmt.Errorf("invalid resolution expression [%s]", toResolve) 144 } 145 146 itemIdx := strings.Index(toResolve[:dotIdx], "[") 147 148 if itemIdx != -1 { 149 details.Item = toResolve[itemIdx+1 : dotIdx-1] 150 details.ResolverName = toResolve[:itemIdx] 151 } else { 152 //For the case to get current scope attribute data 153 if strings.HasPrefix(toResolve, "$.") || strings.HasPrefix(toResolve, ".") { 154 details.ResolverName = toResolve[:dotIdx+1] 155 } else { 156 details.ResolverName = toResolve[:dotIdx] 157 } 158 //special case for activity without brackets 159 if strings.HasPrefix(toResolve, "activity") { 160 nextDot := strings.Index(toResolve[dotIdx+1:], ".") + dotIdx + 1 161 details.Item = toResolve[dotIdx+1 : nextDot] 162 dotIdx = nextDot 163 } 164 } 165 166 pathIdx := strings.IndexFunc(toResolve[dotIdx+1:], isSep) 167 168 if pathIdx != -1 { 169 pathStart := pathIdx + dotIdx + 1 170 details.Path = toResolve[pathStart:] 171 details.Property = toResolve[dotIdx+1 : pathStart] 172 } else { 173 details.Property = toResolve[dotIdx+1:] 174 } 175 176 return details, nil 177 } 178 179 func GetResolutionDetailsOld(toResolve string) (*ResolutionDetails, error) { 180 181 //todo optimize, maybe tokenize first 182 183 closeIdx := strings.Index(toResolve, "}") 184 185 if len(toResolve) < 4 || closeIdx == -1 { 186 return nil, fmt.Errorf("invalid resolution expression [%s]", toResolve) 187 } 188 189 details := &ResolutionDetails{} 190 191 dotIdx := strings.Index(toResolve, ".") 192 193 if dotIdx == -1 { 194 return nil, fmt.Errorf("invalid resolution expression [%s]", toResolve) 195 } 196 197 details.ResolverName = toResolve[2:dotIdx] 198 199 if details.ResolverName == "activity" { 200 nextDot := strings.Index(toResolve[dotIdx+1:], ".") + dotIdx + 1 201 details.Item = toResolve[dotIdx+1 : nextDot] 202 dotIdx = nextDot 203 } 204 details.Property = toResolve[dotIdx+1 : closeIdx] 205 206 if closeIdx+1 < len(toResolve) { 207 details.Path = toResolve[closeIdx+1:] 208 } 209 210 return details, nil 211 } 212 213 func isSep(r rune) bool { 214 return r == '.' || r == '[' 215 } 216 217 func GetValueWithResolver(valueMap map[string]interface{}, key string) (interface{}, bool) { 218 219 val, exists := valueMap[key] 220 221 if !exists { 222 return nil, false 223 } 224 225 strVal, ok := val.(string) 226 227 if ok { 228 if strVal == "" { 229 return "", true 230 } 231 232 if strVal[0] == '$' { 233 234 v, err := GetBasicResolver().Resolve(strVal, nil) 235 if err != nil { 236 if strings.HasPrefix(err.Error(), "unsupported resolver") { 237 return val, true 238 } 239 //todo double check this case 240 return val, true 241 } 242 243 return v, true 244 } else { 245 return val, true 246 } 247 } 248 249 return val, true 250 } 251 252 func GetComplexValue(value interface{}) interface{} { 253 if value != nil { 254 switch t := value.(type) { 255 case *ComplexObject: 256 return t.Value 257 } 258 } 259 return value 260 }