8 // Controller registry and types.
9 type ControllerType struct {
10 Namespace string // The namespace of the controller
11 ModuleSource *Module // The module for the controller
14 ControllerIndexes [][]int // FieldByIndex to all embedded *Controllers
15 ControllerEvents *ControllerTypeEvents
17 type ControllerTypeEvents struct {
18 Before, After, Finally, Panic []*ControllerFieldPath
21 // The controller field path provides the caller the ability to invoke the call
23 type ControllerFieldPath struct {
26 FunctionCall reflect.Value
29 type MethodType struct {
32 RenderArgNames map[int][]string
37 type MethodArg struct {
42 // Adds the controller to the controllers map using its namespace, also adds it to the module list of controllers.
43 // If the controller is in the main application it is added without its namespace as well.
44 func AddControllerType(moduleSource *Module, controllerType reflect.Type, methods []*MethodType) (newControllerType *ControllerType) {
45 if moduleSource == nil {
46 moduleSource = appModule
49 newControllerType = &ControllerType{ModuleSource: moduleSource, Type: controllerType, Methods: methods, ControllerIndexes: findControllers(controllerType)}
50 newControllerType.ControllerEvents = NewControllerTypeEvents(newControllerType)
51 newControllerType.Namespace = moduleSource.Namespace()
52 controllerName := newControllerType.Name()
54 // Store the first controller only in the controllers map with the unmapped namespace.
55 if _, found := controllers[controllerName]; !found {
56 controllers[controllerName] = newControllerType
57 newControllerType.ModuleSource.AddController(newControllerType)
58 if newControllerType.ModuleSource == appModule {
59 // Add the controller mapping into the global namespace
60 controllers[newControllerType.ShortName()] = newControllerType
63 controllerLog.Errorf("Error, attempt to register duplicate controller as %s", controllerName)
65 controllerLog.Debugf("Registered controller: %s", controllerName)
70 // Method searches for a given exported method (case insensitive)
71 func (ct *ControllerType) Method(name string) *MethodType {
72 lowerName := strings.ToLower(name)
73 for _, method := range ct.Methods {
74 if method.lowerName == lowerName {
81 // The controller name with the namespace
82 func (ct *ControllerType) Name() string {
83 return ct.Namespace + ct.ShortName()
86 // The controller name without the namespace
87 func (ct *ControllerType) ShortName() string {
88 return strings.ToLower(ct.Type.Name())
91 func NewControllerTypeEvents(c *ControllerType) (ce *ControllerTypeEvents) {
92 ce = &ControllerTypeEvents{}
93 // Parse the methods for the controller type, assign any control methods
95 ce.check(checkType, []int{})
99 // Add in before after panic and finally, recursive call
100 // Befores are ordered in revers, everything else is in order of first encountered
101 func (cte *ControllerTypeEvents) check(theType reflect.Type, fieldPath []int) {
102 typeChecker := func(checkType reflect.Type) {
103 for index := 0; index < checkType.NumMethod(); index++ {
104 m := checkType.Method(index)
105 // Must be two arguments, the second returns the controller type
106 // Go cannot differentiate between promoted methods and
107 // embedded methods, this allows the embedded method to be run
108 // https://github.com/golang/go/issues/21162
109 if m.Type.NumOut() == 2 && m.Type.Out(1) == checkType {
110 if checkType.Kind() == reflect.Ptr {
111 controllerLog.Debug("Found controller type event method pointer", "name", checkType.Elem().Name(), "methodname", m.Name)
113 controllerLog.Debug("Found controller type event method", "name", checkType.Name(), "methodname", m.Name)
115 controllerFieldPath := newFieldPath(checkType.Kind() == reflect.Ptr, m.Func, fieldPath)
116 switch strings.ToLower(m.Name) {
118 cte.Before = append([]*ControllerFieldPath{controllerFieldPath}, cte.Before...)
120 cte.After = append(cte.After, controllerFieldPath)
122 cte.Panic = append(cte.Panic, controllerFieldPath)
124 cte.Finally = append(cte.Finally, controllerFieldPath)
130 // Check methods of both types
132 typeChecker(reflect.PtrTo(theType))
134 // Check for any sub controllers, ignore any pointers to controllers revel.Controller
135 for i := 0; i < theType.NumField(); i++ {
136 v := theType.Field(i)
138 switch v.Type.Kind() {
140 cte.check(v.Type, append(fieldPath, i))
144 func newFieldPath(isPointer bool, value reflect.Value, fieldPath []int) *ControllerFieldPath {
145 return &ControllerFieldPath{IsPointer: isPointer, FunctionCall: value, FieldIndexPath: fieldPath}
148 func (fieldPath *ControllerFieldPath) Invoke(value reflect.Value, input []reflect.Value) (result []reflect.Value) {
149 for _, index := range fieldPath.FieldIndexPath {
150 // You can only fetch fields from non pointers
151 if value.Type().Kind() == reflect.Ptr {
152 value = value.Elem().Field(index)
154 value = value.Field(index)
157 if fieldPath.IsPointer && value.Type().Kind() != reflect.Ptr {
159 } else if !fieldPath.IsPointer && value.Type().Kind() == reflect.Ptr {
163 return fieldPath.FunctionCall.Call(append([]reflect.Value{value}, input...))