github.com/TIBCOSoftware/flogo-lib@v0.5.9/core/mapper/exprmapper/expression/function/function.go (about) 1 package function 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/TIBCOSoftware/flogo-lib/core/data" 7 "github.com/TIBCOSoftware/flogo-lib/core/mapper/exprmapper/expression/expr" 8 "github.com/TIBCOSoftware/flogo-lib/logger" 9 "reflect" 10 "runtime/debug" 11 ) 12 13 var logrus = logger.GetLogger("function") 14 15 type Func interface { 16 Eval(inputScope, outputScope data.Scope) ([]interface{}, error) 17 String() string 18 } 19 20 type FunctionExp struct { 21 Name string `json:"name"` 22 Params []*Parameter `json:"params"` 23 } 24 25 type Parameter struct { 26 Value expr.Expr `json:"value"` 27 } 28 29 func (f *FunctionExp) Eval() (interface{}, error) { 30 value, err := f.callFunction(nil, nil, nil) 31 if err != nil { 32 return nil, err 33 } 34 return convertType(value), err 35 } 36 37 func (f *FunctionExp) EvalWithScope(inputScope data.Scope, resolver data.Resolver) (interface{}, error) { 38 39 value, err := f.callFunction(nil, inputScope, resolver) 40 if err != nil { 41 logrus.Errorf("Execution failed for function [%s] error - %+v", f.Name, err.Error()) 42 return nil, err 43 } 44 return convertType(value), err 45 } 46 47 func (f *FunctionExp) EvalWithData(data interface{}, inputScope data.Scope, resolver data.Resolver) (interface{}, error) { 48 value, err := f.callFunction(data, inputScope, resolver) 49 if err != nil { 50 return nil, err 51 } 52 return convertType(value), err 53 } 54 55 func HandleToSingleOutput(values interface{}) interface{} { 56 if values != nil { 57 switch t := values.(type) { 58 case []interface{}: 59 return t[0] 60 default: 61 return t 62 } 63 } 64 return nil 65 } 66 67 func convertType(value reflect.Value) interface{} { 68 return value.Interface() 69 } 70 71 func (f *FunctionExp) getRealFunction() (Function, error) { 72 return GetFunction(f.Name) 73 } 74 75 func (f *FunctionExp) getMethod() (reflect.Value, error) { 76 var ptr reflect.Value 77 s, err := f.getRealFunction() 78 if err != nil { 79 return reflect.Value{}, err 80 } 81 82 value := reflect.ValueOf(s) 83 if value.Type().Kind() == reflect.Ptr { 84 ptr = value 85 value = ptr.Elem() 86 } else { 87 ptr = reflect.New(reflect.TypeOf(s)) 88 temp := ptr.Elem() 89 temp.Set(value) 90 } 91 92 method := value.MethodByName("Eval") 93 if !method.IsValid() { 94 method = ptr.MethodByName("Eval") 95 if !method.IsValid() { 96 logrus.Debug("invalid also, ", f.Name) 97 return reflect.Value{}, errors.New("Method invalid..") 98 99 } 100 } 101 102 return method, nil 103 } 104 105 func (f *FunctionExp) callFunction(fdata interface{}, inputScope data.Scope, resolver data.Resolver) (results reflect.Value, err error) { 106 defer func() { 107 if r := recover(); r != nil { 108 err = fmt.Errorf("%+v", r) 109 logrus.Debugf("StackTrace: %s", debug.Stack()) 110 } 111 }() 112 113 method, err := f.getMethod() 114 if err != nil { 115 return reflect.Value{}, err 116 } 117 118 inputs := []reflect.Value{} 119 for _, p := range f.Params { 120 result, err := p.Value.EvalWithData(fdata, inputScope, resolver) 121 if err != nil { 122 return reflect.Value{}, err 123 } 124 125 logrus.Debugf("function [%s] [%d]'s argument value [%+v]", f.Name, result) 126 inputs = append(inputs, reflect.ValueOf(result)) 127 } 128 129 logrus.Debugf("Input Parameters: %+v", inputs) 130 args, err := ensureArguments(method, inputs) 131 if err != nil { 132 return reflect.Value{}, fmt.Errorf("Function '%s' argument validation failed due to error %s", f.Name, err.Error()) 133 } 134 values := method.Call(args) 135 return f.extractErrorFromValues(values) 136 } 137 138 func ensureArguments(method reflect.Value, in []reflect.Value) ([]reflect.Value, error) { 139 140 var retInputs []reflect.Value 141 methodType := method.Type() 142 n := method.Type().NumIn() 143 144 if methodType.IsVariadic() && n == 1 { 145 x := in[0] 146 elem := methodType.In(0).Elem() 147 if xt := x.Type(); !xt.AssignableTo(elem) { 148 v, err := convertArgs(elem, x) 149 if err != nil { 150 return nil, fmt.Errorf("argument type mismatch. Can not convert type %s to type %s. ", xt.String(), elem.String()) 151 } 152 retInputs = append(retInputs, reflect.ValueOf(v)) 153 } else { 154 retInputs = append(retInputs, x) 155 } 156 } else { 157 for i := 0; i < n; i++ { 158 if xt, targ := in[i].Type(), methodType.In(i); !xt.AssignableTo(targ) { 159 v, err := convertArgs(targ, in[i]) 160 if err != nil { 161 return nil, fmt.Errorf("argument type mismatch. Can not convert type %s to type %s. ", xt.String(), targ.String()) 162 } 163 retInputs = append(retInputs, reflect.ValueOf(v)) 164 } else { 165 retInputs = append(retInputs, in[i]) 166 } 167 } 168 } 169 170 if methodType.IsVariadic() { 171 m := len(in) - n 172 elem := methodType.In(n - 1).Elem() 173 for j := 0; j < m; j++ { 174 x := in[n+j] 175 emtpy := reflect.Value{} 176 if x == emtpy { 177 retInputs = append(retInputs, reflect.Zero(elem)) 178 } else { 179 if xt := x.Type(); !xt.AssignableTo(elem) { 180 v, err := convertArgs(elem, x) 181 if err != nil { 182 return nil, fmt.Errorf("argument type mismatch. Can not convert type %s to type %s. ", xt.String(), elem.String()) 183 } 184 retInputs = append(retInputs, reflect.ValueOf(v)) 185 } else { 186 retInputs = append(retInputs, x) 187 } 188 } 189 190 } 191 } 192 193 return retInputs, nil 194 } 195 196 func convertArgs(argType reflect.Type, in reflect.Value) (interface{}, error) { 197 var v interface{} 198 var err error 199 switch argType.Kind() { 200 case reflect.Bool: 201 v, err = data.CoerceToBoolean(in.Interface()) 202 case reflect.Interface: 203 v, err = data.CoerceToAny(in.Interface()) 204 case reflect.Int: 205 v, err = data.CoerceToInteger(in.Interface()) 206 case reflect.Int64: 207 v, err = data.CoerceToLong(in.Interface()) 208 case reflect.String: 209 v, err = data.CoerceToString(in.Interface()) 210 case reflect.Float64: 211 v, err = data.CoerceToDouble(in.Interface()) 212 default: 213 v = in.Interface() 214 } 215 return v, err 216 217 } 218 219 func (f *FunctionExp) extractErrorFromValues(values []reflect.Value) (reflect.Value, error) { 220 tempValues := []reflect.Value{} 221 222 var err error 223 for _, value := range values { 224 if value.Type().Name() == "error" { 225 if value.Interface() != nil { 226 err = value.Interface().(error) 227 } 228 } else { 229 tempValues = append(tempValues, value) 230 } 231 } 232 233 if len(tempValues) > 1 { 234 return tempValues[0], fmt.Errorf("Not support function multiple returns") 235 } 236 return tempValues[0], err 237 }