6
"launchpad.net/juju-core/log"
11
errorType = reflect.TypeOf((*error)(nil)).Elem()
12
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
13
stringType = reflect.TypeOf("")
16
var errNilDereference = errors.New("field retrieval from nil reference")
18
// Server represents an RPC server.
20
// root holds the default root value.
23
// obtain maps from root-object method name to
24
// information about that method. The term "obtain"
25
// is because these methods obtain an object to
27
obtain map[string]*obtainer
29
// action maps from an object type (as returned by
30
// an obtainer method) to the set of methods on an
31
// object of that type, with information about each
33
action map[reflect.Type]map[string]*action
35
// transformErrors is used to process all errors sent to
37
transformErrors func(error) error
40
// NewServer returns a new server that will serve requests
41
// by invoking methods on values of the same type as rootValue.
42
// Actual values of rootValue may be provided for
43
// each client connection (see ServeCodec and Accept),
44
// or rootValue may be used directly if no such values are
47
// The server executes each client request by calling a "type" method on
48
// a root value to obtain an object to act on; then it invokes an
49
// action method on that object with the request parameters, possibly
50
// returning some result.
52
// Type methods on the root value are of the form:
54
// M(id string) (O, error)
56
// where M is an exported name, conventionally naming the object type,
57
// id is some identifier for the object and O is the type of the
60
// Request methods defined on O may defined in one of the following
61
// forms, where T and R must be struct types.
65
// Method() (R, error)
69
// Method(T) (R, error)
72
// If transformErrors is non-nil, it will be called on all returned
73
// non-nil errors, for example to transform the errors into ServerErrors
74
// with specified codes. There will be a panic if transformErrors
76
func NewServer(rootValue interface{}, transformErrors func(error) error) (*Server, error) {
77
if transformErrors == nil {
78
transformErrors = func(e error) error { return e }
81
root: reflect.ValueOf(rootValue),
82
obtain: make(map[string]*obtainer),
83
action: make(map[reflect.Type]map[string]*action),
84
transformErrors: transformErrors,
87
for i := 0; i < rt.NumMethod(); i++ {
89
o := srv.methodToObtainer(m)
91
log.Infof("rpc: discarding obtainer method %#v", m)
94
actions := make(map[string]*action)
95
for i := 0; i < o.ret.NumMethod(); i++ {
97
if a := srv.methodToAction(m); a != nil {
100
log.Infof("rpc: discarding action method %#v", m)
103
if len(actions) > 0 {
104
srv.action[o.ret] = actions
105
srv.obtain[m.Name] = o
107
log.Infof("rpc: discarding obtainer %v because its result has no methods", m.Name)
110
if len(srv.obtain) == 0 {
111
return nil, fmt.Errorf("no RPC methods found on %s", rt)
116
// obtainer holds information on a root-level method.
117
type obtainer struct {
118
// ret holds the type of the object returned by the method.
121
// call invokes the obtainer method. The rcvr parameter must be
122
// the same type as the root object. The given id is passed
123
// as an argument to the method.
124
call func(rcvr reflect.Value, id string) (reflect.Value, error)
127
func (o *obtainer) String() string {
128
return fmt.Sprintf("{id -> %s}", o.ret)
131
func (srv *Server) methodToObtainer(m reflect.Method) *obtainer {
138
t.In(1) != stringType ||
139
t.Out(1) != errorType {
142
f := func(rcvr reflect.Value, id string) (r reflect.Value, err error) {
143
out := rcvr.Method(m.Index).Call([]reflect.Value{reflect.ValueOf(id)})
145
err = out[1].Interface().(error)
156
// action holds information about a method on an object
157
// that can be obtained from the root object.
159
// arg holds the argument type of the method, or nil
160
// if there is no argument.
163
// ret holds the return type of the method, or nil
164
// if the method returns no value.
167
// call calls the action method with the given argument
168
// on the given receiver value. If the method does
169
// not return a value, the returned value will not be valid.
170
call func(rcvr, arg reflect.Value) (reflect.Value, error)
173
func (p *action) String() string {
174
return fmt.Sprintf("{%v -> %v}", p.arg, p.ret)
177
func (srv *Server) methodToAction(m reflect.Method) *action {
182
var assemble func(arg reflect.Value) []reflect.Value
183
// N.B. The method type has the receiver as its first argument.
188
assemble = func(arg reflect.Value) []reflect.Value {
194
assemble = func(arg reflect.Value) []reflect.Value {
195
return []reflect.Value{arg}
202
case t.NumOut() == 0:
204
p.call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
205
rcvr.Method(m.Index).Call(assemble(arg))
208
case t.NumOut() == 1 && t.Out(0) == errorType:
210
p.call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
211
out := rcvr.Method(m.Index).Call(assemble(arg))
213
err = out[0].Interface().(error)
217
case t.NumOut() == 1:
220
p.call = func(rcvr, arg reflect.Value) (reflect.Value, error) {
221
out := rcvr.Method(m.Index).Call(assemble(arg))
224
case t.NumOut() == 2 && t.Out(1) == errorType:
225
// Method(...) (R, error)
227
p.call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
228
out := rcvr.Method(m.Index).Call(assemble(arg))
231
err = out[1].Interface().(error)
238
if p.arg != nil && p.arg.Kind() != reflect.Struct {
241
if p.ret != nil && p.ret.Kind() != reflect.Struct {