github.com/TIBCOSoftware/flogo-lib@v0.5.9/core/trigger/handler.go (about)

     1  package trigger
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/TIBCOSoftware/flogo-lib/core/action"
     8  	"github.com/TIBCOSoftware/flogo-lib/core/data"
     9  	"github.com/TIBCOSoftware/flogo-lib/core/mapper"
    10  	"github.com/TIBCOSoftware/flogo-lib/logger"
    11  )
    12  
    13  type Handler struct {
    14  	internal HandlerInf
    15  	config   *HandlerConfig
    16  	act      action.Action
    17  }
    18  
    19  type HandlerInf interface {
    20  	Handle(ctx context.Context, triggerData map[string]interface{}) (map[string]*data.Attribute, error)
    21  
    22  	GetSetting(setting string) (interface{}, bool)
    23  
    24  	GetOutput() (map[string]interface{})
    25  
    26  	GetStringSetting(setting string) string
    27  
    28  	String() string
    29  }
    30  
    31  func NewHandler(config *HandlerConfig, act action.Action, outputMd map[string]*data.Attribute, replyMd map[string]*data.Attribute, runner action.Runner) *Handler {
    32  	helper := &handlerHelperImpl{config: config, act: act, outputMd: outputMd, replyMd: replyMd, runner: runner}
    33  	handler := &Handler{internal: helper, config: config, act: act}
    34  
    35  	if config != nil {
    36  		if config.Action.Mappings != nil {
    37  			if len(config.Action.Mappings.Input) > 0 {
    38  				helper.actionInputMapper = mapper.GetFactory().NewMapper(&data.MapperDef{Mappings: config.Action.Mappings.Input}, nil)
    39  			}
    40  			if len(config.Action.Mappings.Output) > 0 {
    41  				helper.actionOutputMapper = mapper.GetFactory().NewMapper(&data.MapperDef{Mappings: config.Action.Mappings.Output}, nil)
    42  			}
    43  		} else if config.ActionMappings != nil {
    44  			// temporary for backwards compatibility
    45  			if len(config.ActionMappings.Input) > 0 {
    46  				helper.actionInputMapper = mapper.GetFactory().NewMapper(&data.MapperDef{Mappings: config.ActionMappings.Input}, nil)
    47  			}
    48  			if len(config.ActionMappings.Output) > 0 {
    49  				helper.actionOutputMapper = mapper.GetFactory().NewMapper(&data.MapperDef{Mappings: config.ActionMappings.Output}, nil)
    50  			}
    51  		}
    52  	}
    53  
    54  	return handler
    55  }
    56  
    57  func (h *Handler) GetSetting(setting string) (interface{}, bool) {
    58  	return h.internal.GetSetting(setting)
    59  }
    60  
    61  func (h *Handler) GetOutput() (map[string]interface{}) {
    62  	return h.internal.GetOutput()
    63  }
    64  
    65  func (h *Handler) GetStringSetting(setting string) string {
    66  	return h.internal.GetStringSetting(setting)
    67  }
    68  
    69  func (h *Handler) Handle(ctx context.Context, triggerData map[string]interface{}) (map[string]*data.Attribute, error) {
    70  
    71  	return h.internal.Handle(ctx, triggerData)
    72  }
    73  
    74  func (h *Handler) String() string {
    75  	return h.internal.String()
    76  }
    77  
    78  func NewHandlerAlt(internal HandlerInf) *Handler {
    79  	return &Handler{internal:internal}
    80  }
    81  
    82  type handlerHelperImpl struct {
    83  	runner action.Runner
    84  	act    action.Action
    85  
    86  	outputMd map[string]*data.Attribute
    87  	replyMd  map[string]*data.Attribute
    88  
    89  	config *HandlerConfig
    90  
    91  	actionInputMapper  data.Mapper
    92  	actionOutputMapper data.Mapper
    93  }
    94  
    95  func (h *handlerHelperImpl) GetSetting(setting string) (interface{}, bool) {
    96  
    97  	if h.config == nil {
    98  		return nil, false
    99  	}
   100  
   101  	val, exists := data.GetValueWithResolver(h.config.Settings, setting)
   102  
   103  	if !exists {
   104  		val, exists = data.GetValueWithResolver(h.config.parent.Settings, setting)
   105  	}
   106  
   107  	return val, exists
   108  }
   109  
   110  func (h *handlerHelperImpl) GetOutput() (map[string]interface{}) {
   111  
   112  	if h.config == nil {
   113  		return nil
   114  	}
   115  	return h.config.Output
   116  }
   117  
   118  func (h *handlerHelperImpl) GetStringSetting(setting string) string {
   119  	val, exists := h.GetSetting(setting)
   120  
   121  	if !exists {
   122  		return ""
   123  	}
   124  
   125  	strVal, err := data.CoerceToString(val)
   126  
   127  	if err != nil {
   128  		return ""
   129  	}
   130  
   131  	return strVal
   132  }
   133  
   134  func (h *handlerHelperImpl) Handle(ctx context.Context, triggerData map[string]interface{}) (map[string]*data.Attribute, error) {
   135  	inputs, err := h.generateInputs(triggerData)
   136  
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	newCtx := NewHandlerContext(ctx, h.config)
   142  	results, err := h.runner.Execute(newCtx, h.act, inputs)
   143  
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	retValue, err := h.generateOutputs(results)
   149  
   150  	return retValue, err
   151  }
   152  
   153  func (h *handlerHelperImpl) dataToAttrs(triggerData map[string]interface{}) ([]*data.Attribute, error) {
   154  	attrs := make([]*data.Attribute, 0, len(h.outputMd))
   155  
   156  	for k, a := range h.outputMd {
   157  		v, _ := triggerData[k]
   158  
   159  		switch t := v.(type) {
   160  		case *data.Attribute:
   161  			attr, err := data.NewAttribute(t.Name(), t.Type(), t.Value())
   162  			if err != nil {
   163  				return nil, err
   164  			}
   165  			attrs = append(attrs, attr)
   166  		default:
   167  			attr, err := data.NewAttribute(a.Name(), a.Type(), v)
   168  			if err != nil {
   169  				return nil, err
   170  			}
   171  			attrs = append(attrs, attr)
   172  		}
   173  	}
   174  
   175  	return attrs, nil
   176  }
   177  
   178  func (h *handlerHelperImpl) generateInputs(triggerData map[string]interface{}) (map[string]*data.Attribute, error) {
   179  
   180  	triggerAttrs, err := h.dataToAttrs(triggerData)
   181  
   182  	if err != nil {
   183  		logger.Errorf("Failed parsing attrs: %s, Error: %s", triggerData, err)
   184  		return nil, err
   185  	}
   186  
   187  	var inputs map[string]*data.Attribute
   188  
   189  	//if h.act.IOMetadata() == nil {
   190  	//	inputs = make(map[string]*data.Attribute, len(triggerAttrs))
   191  	//
   192  	//	for _, attr := range triggerAttrs {
   193  	//		inputs[attr.Name()] = attr
   194  	//	}
   195  	//
   196  	//	return inputs, nil
   197  	//}
   198  	//inputMetadata := h.act.IOMetadata().Input
   199  
   200  	logger.Debugf("iomd %#v", h.act.IOMetadata())
   201  
   202  	//todo verify this behavior
   203  	if h.actionInputMapper != nil && h.act.IOMetadata() != nil && h.act.IOMetadata().Input != nil {
   204  
   205  		inputMetadata := h.act.IOMetadata().Input
   206  
   207  		inScope := data.NewSimpleScope(triggerAttrs, nil)
   208  
   209  		var attrs map[string]*data.Attribute
   210  
   211  		//todo clean this up
   212  		if h.act.Metadata() != nil && h.act.Metadata().Passthru {
   213  			outScope := data.NewFlexableScope(inputMetadata)
   214  
   215  			err := h.actionInputMapper.Apply(inScope, outScope)
   216  			if err != nil {
   217  				return nil, err
   218  			}
   219  
   220  			attrs = outScope.GetAttrs()
   221  
   222  		} else {
   223  			outScope := data.NewFixedScope(inputMetadata)
   224  
   225  			err := h.actionInputMapper.Apply(inScope, outScope)
   226  			if err != nil {
   227  				return nil, err
   228  			}
   229  
   230  			attrs = outScope.GetAttrs()
   231  		}
   232  
   233  		inputs = make(map[string]*data.Attribute, len(attrs))
   234  
   235  		for _, attr := range attrs {
   236  			inputs[attr.Name()] = attr
   237  		}
   238  
   239  	} else {
   240  		// for backwards compatibility make trigger outputs map directly to action inputs
   241  
   242  		logger.Debug("No mapping specified, adding trigger outputs as inputs to action")
   243  
   244  		inputs = make(map[string]*data.Attribute, len(triggerAttrs))
   245  
   246  		for _, attr := range triggerAttrs {
   247  
   248  			logger.Debugf(" Attr: %s, Type: %s, Value: %v", attr.Name(), attr.Type().String(), attr.Value())
   249  			//inputs = append(inputs, data.NewAttribute( attr.Name, attr.Type, attr.Value))
   250  			inputs[attr.Name()] = attr
   251  
   252  			attrName := "_T." + attr.Name()
   253  			inputs[attrName] = data.CloneAttribute(attrName, attr)
   254  		}
   255  
   256  		//Add action metadata into flow
   257  		if h.act.IOMetadata() != nil && h.act.IOMetadata().Input != nil {
   258  			//Adding action metadat into inputs
   259  			for _, attr := range h.act.IOMetadata().Input {
   260  				inputs[attr.Name()] = attr
   261  			}
   262  		}
   263  	}
   264  
   265  	return inputs, nil
   266  }
   267  
   268  func (h *handlerHelperImpl) generateOutputs(actionResults map[string]*data.Attribute) (map[string]*data.Attribute, error) {
   269  
   270  	if len(actionResults) == 0 {
   271  		return nil, nil
   272  	}
   273  
   274  	if h.actionOutputMapper == nil {
   275  		//for backwards compatibility
   276  		return actionResults, nil
   277  	}
   278  
   279  	outputMetadata := h.act.IOMetadata().Output
   280  
   281  	if outputMetadata != nil {
   282  
   283  		outScope := data.NewFixedScopeFromMap(h.replyMd)
   284  		inScope := data.NewSimpleScopeFromMap(actionResults, nil)
   285  
   286  		err := h.actionOutputMapper.Apply(inScope, outScope)
   287  		if err != nil {
   288  			return nil, err
   289  		}
   290  
   291  		return outScope.GetAttrs(), nil
   292  	}
   293  
   294  	return actionResults, nil
   295  }
   296  
   297  func (h *handlerHelperImpl) String() string {
   298  	return fmt.Sprintf("Handler[action:%s]", h.config.Action.Ref)
   299  }