github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/rpc/rpcreflect/value.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package rpcreflect 5 6 import ( 7 "fmt" 8 "reflect" 9 ) 10 11 // CallNotImplementedError is an error, returned an attempt to call to 12 // an unknown API method is made. 13 type CallNotImplementedError struct { 14 Method string 15 RootMethod string 16 } 17 18 func (e *CallNotImplementedError) Error() string { 19 if e.Method == "" { 20 return fmt.Sprintf("unknown object type %q", e.RootMethod) 21 } 22 return fmt.Sprintf("no such request - method %s.%s is not implemented", e.RootMethod, e.Method) 23 } 24 25 // MethodCaller knows how to call a particular RPC method. 26 type MethodCaller struct { 27 // ParamsType holds the required type of the parameter to the object method. 28 ParamsType reflect.Type 29 // ResultType holds the result type of the result of caling the object method. 30 ResultType reflect.Type 31 32 rootValue reflect.Value 33 rootMethod RootMethod 34 objMethod ObjMethod 35 } 36 37 // MethodCaller holds the value of the root of an RPC server that 38 // can call methods directly on a Go value. 39 type Value struct { 40 rootValue reflect.Value 41 rootType *Type 42 } 43 44 // ValueOf returns a value that can be used to call RPC-style 45 // methods on the given root value. It returns the zero 46 // Value if rootValue.IsValid is false. 47 func ValueOf(rootValue reflect.Value) Value { 48 if !rootValue.IsValid() { 49 return Value{} 50 } 51 return Value{ 52 rootValue: rootValue, 53 rootType: TypeOf(rootValue.Type()), 54 } 55 } 56 57 // IsValid returns whether the Value has been initialized with ValueOf. 58 func (v Value) IsValid() bool { 59 return v.rootType != nil 60 } 61 62 // GoValue returns the value that was passed to ValueOf to create v. 63 func (v Value) GoValue() reflect.Value { 64 return v.rootValue 65 } 66 67 // MethodCaller returns an object that can be used to make calls on 68 // the given root value to the given root method and object method. 69 // It returns an error if either the root method or the object 70 // method were not found. 71 // It panics if called on the zero Value. 72 func (v Value) MethodCaller(rootMethodName, objMethodName string) (MethodCaller, error) { 73 if !v.IsValid() { 74 panic("MethodCaller called on invalid Value") 75 } 76 caller := MethodCaller{ 77 rootValue: v.rootValue, 78 } 79 var err error 80 caller.rootMethod, err = v.rootType.Method(rootMethodName) 81 if err != nil { 82 return MethodCaller{}, &CallNotImplementedError{ 83 RootMethod: rootMethodName, 84 } 85 } 86 caller.objMethod, err = caller.rootMethod.ObjType.Method(objMethodName) 87 if err != nil { 88 return MethodCaller{}, &CallNotImplementedError{ 89 RootMethod: rootMethodName, 90 Method: objMethodName, 91 } 92 } 93 caller.ParamsType = caller.objMethod.Params 94 caller.ResultType = caller.objMethod.Result 95 return caller, nil 96 } 97 98 func (caller MethodCaller) Call(objId string, arg reflect.Value) (reflect.Value, error) { 99 obj, err := caller.rootMethod.Call(caller.rootValue, objId) 100 if err != nil { 101 return reflect.Value{}, err 102 } 103 return caller.objMethod.Call(obj, arg) 104 }