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  }