Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / controller_type.go
1 package revel
2
3 import (
4         "reflect"
5         "strings"
6 )
7
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
12         Type              reflect.Type
13         Methods           []*MethodType
14         ControllerIndexes [][]int // FieldByIndex to all embedded *Controllers
15         ControllerEvents  *ControllerTypeEvents
16 }
17 type ControllerTypeEvents struct {
18         Before, After, Finally, Panic []*ControllerFieldPath
19 }
20
21 // The controller field path provides the caller the ability to invoke the call
22 // directly
23 type ControllerFieldPath struct {
24         IsPointer      bool
25         FieldIndexPath []int
26         FunctionCall   reflect.Value
27 }
28
29 type MethodType struct {
30         Name           string
31         Args           []*MethodArg
32         RenderArgNames map[int][]string
33         lowerName      string
34         Index          int
35 }
36
37 type MethodArg struct {
38         Name string
39         Type reflect.Type
40 }
41
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
47         }
48
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()
53
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
61                 }
62         } else {
63                 controllerLog.Errorf("Error, attempt to register duplicate controller as %s", controllerName)
64         }
65         controllerLog.Debugf("Registered controller: %s", controllerName)
66
67         return
68 }
69
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 {
75                         return method
76                 }
77         }
78         return nil
79 }
80
81 // The controller name with the namespace
82 func (ct *ControllerType) Name() string {
83         return ct.Namespace + ct.ShortName()
84 }
85
86 // The controller name without the namespace
87 func (ct *ControllerType) ShortName() string {
88         return strings.ToLower(ct.Type.Name())
89 }
90
91 func NewControllerTypeEvents(c *ControllerType) (ce *ControllerTypeEvents) {
92         ce = &ControllerTypeEvents{}
93         // Parse the methods for the controller type, assign any control methods
94         checkType := c.Type
95         ce.check(checkType, []int{})
96         return
97 }
98
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)
112                                 } else {
113                                         controllerLog.Debug("Found controller type event method", "name", checkType.Name(), "methodname", m.Name)
114                                 }
115                                 controllerFieldPath := newFieldPath(checkType.Kind() == reflect.Ptr, m.Func, fieldPath)
116                                 switch strings.ToLower(m.Name) {
117                                 case "before":
118                                         cte.Before = append([]*ControllerFieldPath{controllerFieldPath}, cte.Before...)
119                                 case "after":
120                                         cte.After = append(cte.After, controllerFieldPath)
121                                 case "panic":
122                                         cte.Panic = append(cte.Panic, controllerFieldPath)
123                                 case "finally":
124                                         cte.Finally = append(cte.Finally, controllerFieldPath)
125                                 }
126                         }
127                 }
128         }
129
130         // Check methods of both types
131         typeChecker(theType)
132         typeChecker(reflect.PtrTo(theType))
133
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)
137
138                 switch v.Type.Kind() {
139                 case reflect.Struct:
140                         cte.check(v.Type, append(fieldPath, i))
141                 }
142         }
143 }
144 func newFieldPath(isPointer bool, value reflect.Value, fieldPath []int) *ControllerFieldPath {
145         return &ControllerFieldPath{IsPointer: isPointer, FunctionCall: value, FieldIndexPath: fieldPath}
146 }
147
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)
153                 } else {
154                         value = value.Field(index)
155                 }
156         }
157         if fieldPath.IsPointer && value.Type().Kind() != reflect.Ptr {
158                 value = value.Addr()
159         } else if !fieldPath.IsPointer && value.Type().Kind() == reflect.Ptr {
160                 value = value.Elem()
161         }
162
163         return fieldPath.FunctionCall.Call(append([]reflect.Value{value}, input...))
164 }