Skip to content

Commit

Permalink
Use a Plugin to run Interceptors
Browse files Browse the repository at this point in the history
  • Loading branch information
robfig committed Dec 6, 2012
1 parent 7f2db3c commit f7f405a
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 40 deletions.
56 changes: 16 additions & 40 deletions controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import (
)

type Controller struct {
Name string
Type *ControllerType
MethodType *MethodType
Name string // The controller name, e.g. "Application"
Type *ControllerType // A description of the controller type.
MethodType *MethodType // A description of the invoked action type.
AppController interface{} // The controller that was instantiated.

Request *Request
Response *Response
Result Result

Flash Flash // User cookie, cleared after each request.
Flash Flash // User cookie, cleared after 1 request.
Session Session // Session, stored in cookie, signed.
Params *Params // Parameters from URL and form (including multipart).
Args map[string]interface{} // Per-request scratch space.
Expand Down Expand Up @@ -84,41 +86,29 @@ func (c *Controller) Invoke(appControllerPtr reflect.Value, method reflect.Value

// Run the plugins.
plugins.BeforeRequest(c)
if c.Result != nil {
c.Result.Apply(c.Request, c.Response)
return
}

// Calculate the Result by running the interceptors and the action.
resultValue := func() reflect.Value {
// Call the BEFORE interceptors
result := c.invokeInterceptors(BEFORE, appControllerPtr)
if result != nil {
return reflect.ValueOf(result)
}

// Invoke the action.
resultValue := method.Call(methodArgs)[0]

// Call the AFTER interceptors
result = c.invokeInterceptors(AFTER, appControllerPtr)
if result != nil {
return reflect.ValueOf(result)
}
return resultValue
}()
// Invoke the action.
resultValue := method.Call(methodArgs)[0]
c.Result = resultValue.Interface().(Result)

plugins.AfterRequest(c)

if resultValue.Kind() == reflect.Interface && resultValue.IsNil() {
// if resultValue.Kind() == reflect.Interface && resultValue.IsNil() {
if c.Result == nil {
return
}
result := resultValue.Interface().(Result)

// Apply the result, which generally results in the ResponseWriter getting written.
result.Apply(c.Request, c.Response)
c.Result.Apply(c.Request, c.Response)
}

// This function handles a panic in an action invocation.
// It cleans up the stack trace, logs it, and displays an error page.
func handleInvocationPanic(c *Controller, err interface{}) {
c.invokeInterceptors(PANIC, reflect.ValueOf(c))
plugins.OnException(c, err)
stack := string(debug.Stack())
ERROR.Println(err, "\n", stack)
Expand All @@ -133,20 +123,6 @@ func handleInvocationPanic(c *Controller, err interface{}) {
c.RenderError(error).Apply(c.Request, c.Response)
}

func (c *Controller) invokeInterceptors(when InterceptTime, appControllerPtr reflect.Value) Result {
var result Result
for _, intc := range getInterceptors(when, appControllerPtr) {
resultValue := intc.Invoke(appControllerPtr)
if !resultValue.IsNil() {
result = resultValue.Interface().(Result)
}
if when == BEFORE && result != nil {
return result
}
}
return result
}

func (c *Controller) RenderError(err error) Result {
return ErrorResult{c.RenderArgs, err}
}
Expand Down
41 changes: 41 additions & 0 deletions intercept.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,47 @@ func (i Interception) Invoke(val reflect.Value) reflect.Value {
return vals[0]
}

type InterceptorPlugin struct {
EmptyPlugin
}

func (p InterceptorPlugin) BeforeRequest(c *Controller) {
invokeInterceptors(BEFORE, c)
}

func (p InterceptorPlugin) AfterRequest(c *Controller) {
invokeInterceptors(AFTER, c)
}

func (p InterceptorPlugin) OnException(c *Controller, err interface{}) {
invokeInterceptors(PANIC, c)
}

func init() {
RegisterPlugin(InterceptorPlugin{})
}

func invokeInterceptors(when InterceptTime, c *Controller) {
appControllerPtr := reflect.ValueOf(c.AppController)
result := func() Result {
var result Result
for _, intc := range getInterceptors(when, appControllerPtr) {
resultValue := intc.Invoke(appControllerPtr)
if !resultValue.IsNil() {
result = resultValue.Interface().(Result)
}
if when == BEFORE && result != nil {
return result
}
}
return result
}()

if result != nil {
appControllerPtr.FieldByName("Result").Set(reflect.ValueOf(result))
}
}

var interceptors []*Interception

// Install a general interceptor.
Expand Down
1 change: 1 addition & 0 deletions mvc.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func NewAppController(req *Request, resp *Response, controllerName, methodName s
appControllerPtr := initNewAppController(appControllerType.Type, controller)

// Set the method being called.
controller.AppController = appControllerPtr.Interface()
controller.MethodType = appControllerType.Method(methodName)
if controller.MethodType == nil {
INFO.Println("Failed to find method", methodName, "on Controller",
Expand Down

0 comments on commit f7f405a

Please sign in to comment.