Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature invoke activity #73

Closed
wants to merge 18 commits into from
Closed
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion common/model/tuple.go
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ type Tuple interface {
GetBool(name string) (val bool, err error)
//GetDateTime(name string) time.Time
GetKey() TupleKey
GetMap() map[string]interface{}
}

//MutableTuple mutable part of the tuple
@@ -210,7 +211,7 @@ func (t *tupleImpl) initTupleWithKeyValues(td *TupleDescriptor, values ...interf
t.key = tk
//populate the tuple key fields with the key values
for _, keyProp := range td.GetKeyProps() {
t.tuples [keyProp] = tk.GetValue(keyProp)
t.tuples[keyProp] = tk.GetValue(keyProp)
}
return err
}
@@ -273,3 +274,7 @@ func (t *tupleImpl) isKeyProp(propName string) bool {
}
return found
}

func (t *tupleImpl) GetMap() map[string]interface{} {
return t.tuples
}
17 changes: 10 additions & 7 deletions common/model/types.go
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ type Rule interface {
GetName() string
GetIdentifiers() []TupleType
GetConditions() []Condition
GetActionFn() ActionFunction
GetActionService() ActionService
String() string
GetPriority() int
GetDeps() map[TupleType]map[string]bool
@@ -23,7 +23,7 @@ type Rule interface {
type MutableRule interface {
Rule
AddCondition(conditionName string, idrs []string, cFn ConditionEvaluator, ctx RuleContext) (err error)
SetAction(actionFn ActionFunction)
SetActionService(actionService ActionService)
SetPriority(priority int)
SetContext(ctx RuleContext)
}
@@ -71,7 +71,6 @@ type RuleSession interface {

//RtcTransactionHandler
RegisterRtcTransactionHandler(txnHandler RtcTransactionHandler, handlerCtx interface{})

}

//ConditionEvaluator is a function pointer for handling condition evaluations on the server side
@@ -82,6 +81,12 @@ type ConditionEvaluator func(string, string, map[TupleType]Tuple, RuleContext) b
//i.e part of the server side API
type ActionFunction func(context.Context, RuleSession, string, map[TupleType]Tuple, RuleContext)

// ActionService action service
type ActionService interface {
SetInput(input map[string]interface{})
Execute(context.Context, RuleSession, string, map[TupleType]Tuple, RuleContext) (done bool, err error)
}

//StartupRSFunction is called once after creation of a RuleSession
type StartupRSFunction func(ctx context.Context, rs RuleSession, sessionCtx map[string]interface{}) (err error)

@@ -92,16 +97,14 @@ type ValueChangeListener interface {

type RtcTxn interface {
//map of type and map of key/tuple
GetRtcAdded () map[string]map[string]Tuple
GetRtcAdded() map[string]map[string]Tuple
GetRtcModified() map[string]map[string]RtcModified
GetRtcDeleted() map[string]map[string]Tuple

}

type RtcModified interface {
GetTuple() Tuple
GetModifiedProps() map[string]bool
}

type RtcTransactionHandler func (ctx context.Context, rs RuleSession, txn RtcTxn, txnContext interface{})

type RtcTransactionHandler func(ctx context.Context, rs RuleSession, txn RtcTxn, txnContext interface{})
110 changes: 98 additions & 12 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -3,30 +3,42 @@ package config
import (
"bytes"
"encoding/json"
"fmt"
"strconv"

"github.com/project-flogo/core/data/metadata"
"github.com/project-flogo/rules/common/model"
)

const (
// TypeServiceFunction function based rule service
TypeServiceFunction = "function"
// TypeServiceActivity activity based rule service
TypeServiceActivity = "activity"
// TypeServiceAction action based rule service
TypeServiceAction = "action"
)

// RuleSessionDescriptor is a collection of rules to be loaded

type RuleActionDescriptor struct {
Name string `json:"name"`
IOMetadata *metadata.IOMetadata `json:"metadata"`
Rules []*RuleDescriptor `json:"rules"`
Services []*ServiceDescriptor `json:"services,omitempty"`
}

type RuleSessionDescriptor struct {
Rules []*RuleDescriptor `json:"rules"`
Rules []*RuleDescriptor `json:"rules"`
Services []*ServiceDescriptor `json:"services,omitempty"`
}

// RuleDescriptor defines a rule
type RuleDescriptor struct {
Name string
Conditions []*ConditionDescriptor
ActionFunc model.ActionFunction
Priority int
Name string
Conditions []*ConditionDescriptor
ActionService *ActionServiceDescriptor
Priority int
}

// ConditionDescriptor defines a condition in a rule
@@ -36,12 +48,29 @@ type ConditionDescriptor struct {
Evaluator model.ConditionEvaluator
}

// ActionServiceDescriptor defines rule action service
type ActionServiceDescriptor struct {
Service string `json:"service"`
Input map[string]interface{} `json:"input,omitempty"`
}

// ServiceDescriptor defines a functional target that may be invoked by a rule
type ServiceDescriptor struct {
Name string
Description string
Type string
Function model.ActionFunction
Ref string
Settings map[string]interface{}
}

// UnmarshalJSON unmarshals JSON into struct RuleDescriptor
func (c *RuleDescriptor) UnmarshalJSON(d []byte) error {
ser := &struct {
Name string `json:"name"`
Conditions []*ConditionDescriptor `json:"conditions"`
ActionFuncId string `json:"actionFunction"`
Priority int `json:"priority"`
Name string `json:"name"`
Conditions []*ConditionDescriptor `json:"conditions"`
ActionService *ActionServiceDescriptor `json:"actionService,omitempty"`
Priority int `json:"priority"`
}{}

if err := json.Unmarshal(d, ser); err != nil {
@@ -50,12 +79,13 @@ func (c *RuleDescriptor) UnmarshalJSON(d []byte) error {

c.Name = ser.Name
c.Conditions = ser.Conditions
c.ActionFunc = GetActionFunction(ser.ActionFuncId)
c.ActionService = ser.ActionService
c.Priority = ser.Priority

return nil
}

// MarshalJSON returns JSON encoding of RuleDescriptor
func (c *RuleDescriptor) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString("{")
buffer.WriteString("\"name\":" + "\"" + c.Name + "\",")
@@ -70,13 +100,16 @@ func (c *RuleDescriptor) MarshalJSON() ([]byte, error) {
buffer.Truncate(buffer.Len() - 1)
buffer.WriteString("],")

actionFunctionID := GetActionFunctionID(c.ActionFunc)
buffer.WriteString("\"actionFunction\":\"" + actionFunctionID + "\",")
jsonActionService, err := json.Marshal(c.ActionService)
if err == nil {
buffer.WriteString("\"actionService\":" + string(jsonActionService) + ",")
}
buffer.WriteString("\"priority\":" + strconv.Itoa(c.Priority) + "}")

return buffer.Bytes(), nil
}

// UnmarshalJSON unmarshals JSON into struct ConditionDescriptor
func (c *ConditionDescriptor) UnmarshalJSON(d []byte) error {
ser := &struct {
Name string `json:"name"`
@@ -95,6 +128,7 @@ func (c *ConditionDescriptor) UnmarshalJSON(d []byte) error {
return nil
}

// MarshalJSON returns JSON encoding of ConditionDescriptor
func (c *ConditionDescriptor) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString("{")
buffer.WriteString("\"name\":" + "\"" + c.Name + "\",")
@@ -111,6 +145,58 @@ func (c *ConditionDescriptor) MarshalJSON() ([]byte, error) {
return buffer.Bytes(), nil
}

// UnmarshalJSON unmarshals JSON into struct ServiceDescriptor
func (sd *ServiceDescriptor) UnmarshalJSON(d []byte) error {
ser := &struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Type string `json:"type"`
FunctionID string `json:"function,omitempty"`
Ref string `json:"ref"`
Settings map[string]interface{} `json:"settings,omitempty"`
}{}

if err := json.Unmarshal(d, ser); err != nil {
return err
}

sd.Name = ser.Name
sd.Description = ser.Description
if ser.Type == TypeServiceFunction || ser.Type == TypeServiceActivity || ser.Type == TypeServiceAction {
sd.Type = ser.Type
} else {
return fmt.Errorf("unsupported type - '%s' is referenced in the service '%s'", ser.Type, ser.Name)
}
if ser.FunctionID != "" {
fn := GetActionFunction(ser.FunctionID)
if fn == nil {
return fmt.Errorf("function - '%s' not found", ser.FunctionID)
}
sd.Function = fn
}
sd.Ref = ser.Ref
sd.Settings = ser.Settings

return nil
}

// MarshalJSON returns JSON encoding of ServiceDescriptor
func (sd *ServiceDescriptor) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString("{")
buffer.WriteString("\"name\":" + "\"" + sd.Name + "\",")
buffer.WriteString("\"description\":" + "\"" + sd.Description + "\",")
buffer.WriteString("\"type\":" + "\"" + sd.Type + "\",")
functionID := GetActionFunctionID(sd.Function)
buffer.WriteString("\"function\":" + "\"" + functionID + "\",")
buffer.WriteString("\"ref\":" + "\"" + sd.Ref + "\",")
jsonSettings, err := json.Marshal(sd.Settings)
if err == nil {
buffer.WriteString("\"settings\":" + string(jsonSettings) + "}")
}

return buffer.Bytes(), nil
}

//metadata support
type DefinitionConfig struct {
Name string `json:"name"`
55 changes: 43 additions & 12 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -21,7 +21,9 @@ var testRuleSessionDescriptorJson = `{
"evaluator": "checkForBob"
}
],
"actionFunction": "checkForBobAction"
"actionService": {
"service": "checkForBobService"
}
},
{
"name": "n1.name == Bob && n1.name == n2.name",
@@ -39,8 +41,24 @@ var testRuleSessionDescriptorJson = `{
"evaluator": "checkSameNamesCondition"
}
],
"actionFunction": "checkSameNamesAction"
"actionService": {
"service": "checkSameNamesService"
}
}
],
"services": [
{
"name": "checkForBobService",
"description": "service checkForBobService",
"type": "function",
"function": "checkForBobAction"
},
{
"name": "checkSameNamesService",
"description": "service checkSameNamesService",
"type": "function",
"function": "checkSameNamesAction"
}
]
}
`
@@ -59,35 +77,32 @@ func TestDeserialize(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, ruleSessionDescriptor.Rules)
assert.Equal(t, 2, len(ruleSessionDescriptor.Rules))
assert.Equal(t, 2, len(ruleSessionDescriptor.Services))

// rule-0
r1Cfg := ruleSessionDescriptor.Rules[0]

assert.Equal(t, "n1.name == Bob", r1Cfg.Name)
assert.NotNil(t, r1Cfg.Conditions)
assert.Equal(t, 1, len(r1Cfg.Conditions))

sf1 := reflect.ValueOf(checkForBobAction)
sf2 := reflect.ValueOf(r1Cfg.ActionFunc)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())
assert.Equal(t, "checkForBobService", r1Cfg.ActionService.Service)

r1c1Cfg := r1Cfg.Conditions[0]
assert.Equal(t, "c1", r1c1Cfg.Name)
assert.NotNil(t, r1c1Cfg.Identifiers)
assert.Equal(t, 1, len(r1c1Cfg.Identifiers))

sf1 = reflect.ValueOf(checkForBob)
sf2 = reflect.ValueOf(r1c1Cfg.Evaluator)
sf1 := reflect.ValueOf(checkForBob)
sf2 := reflect.ValueOf(r1c1Cfg.Evaluator)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())

// rule-1
r2Cfg := ruleSessionDescriptor.Rules[1]

assert.Equal(t, "n1.name == Bob && n1.name == n2.name", r2Cfg.Name)
assert.NotNil(t, r2Cfg.Conditions)
assert.Equal(t, 2, len(r2Cfg.Conditions))

sf1 = reflect.ValueOf(checkSameNamesAction)
sf2 = reflect.ValueOf(r2Cfg.ActionFunc)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())
assert.Equal(t, "checkSameNamesService", r2Cfg.ActionService.Service)

r2c1Cfg := r2Cfg.Conditions[0]
assert.Equal(t, "c1", r2c1Cfg.Name)
@@ -106,6 +121,22 @@ func TestDeserialize(t *testing.T) {
sf1 = reflect.ValueOf(checkSameNamesCondition)
sf2 = reflect.ValueOf(r2c2Cfg.Evaluator)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())

// service-0
s1Cfg := ruleSessionDescriptor.Services[0]
assert.Equal(t, "checkForBobService", s1Cfg.Name)
assert.Equal(t, "service checkForBobService", s1Cfg.Description)
sf1 = reflect.ValueOf(checkForBobAction)
sf2 = reflect.ValueOf(s1Cfg.Function)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())

// service-1
s2Cfg := ruleSessionDescriptor.Services[1]
assert.Equal(t, "checkSameNamesService", s2Cfg.Name)
assert.Equal(t, "service checkSameNamesService", s2Cfg.Description)
sf1 = reflect.ValueOf(checkSameNamesAction)
sf2 = reflect.ValueOf(s2Cfg.Function)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())
}

// TEST FUNCTIONS
3 changes: 2 additions & 1 deletion config/manager.go
Original file line number Diff line number Diff line change
@@ -43,7 +43,8 @@ func (m *ResourceManager) GetResource(id string) interface{} {
func (m *ResourceManager) GetRuleSessionDescriptor(uri string) (*RuleSessionDescriptor, error) {

if strings.HasPrefix(uri, uriSchemeRes) {
return &RuleSessionDescriptor{m.configs[uri[len(uriSchemeRes):]].Rules}, nil
id := uri[len(uriSchemeRes):]
return &RuleSessionDescriptor{Rules: m.configs[id].Rules, Services: m.configs[id].Services}, nil
}

return nil, errors.New("cannot find RuleSession: " + uri)
Loading