github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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 the error returned when an attempt to call to 12 // an unknown API method is made. 13 type CallNotImplementedError struct { 14 RootMethod string 15 Version int 16 Method string 17 } 18 19 func (e *CallNotImplementedError) Error() string { 20 if e.Method == "" { 21 if e.Version != 0 { 22 return fmt.Sprintf("unknown version (%d) of interface %q", e.Version, e.RootMethod) 23 } 24 return fmt.Sprintf("unknown object type %q", e.RootMethod) 25 } 26 methodVersion := e.RootMethod 27 if e.Version != 0 { 28 methodVersion = fmt.Sprintf("%s(%d)", e.RootMethod, e.Version) 29 } 30 return fmt.Sprintf("no such request - method %s.%s is not implemented", methodVersion, e.Method) 31 } 32 33 // methodCaller knows how to call a particular RPC method. 34 type methodCaller struct { 35 // paramsType holds the required type of the parameter to the object method. 36 paramsType reflect.Type 37 // resultType holds the result type of the result of caling the object method. 38 resultType reflect.Type 39 40 rootValue reflect.Value 41 rootMethod RootMethod 42 objMethod ObjMethod 43 } 44 45 // methodCaller holds the value of the root of an RPC server that 46 // can call methods directly on a Go value. 47 type Value struct { 48 rootValue reflect.Value 49 rootType *Type 50 } 51 52 // ValueOf returns a value that can be used to call RPC-style 53 // methods on the given root value. It returns the zero 54 // Value if rootValue.IsValid is false. 55 func ValueOf(rootValue reflect.Value) Value { 56 if !rootValue.IsValid() { 57 return Value{} 58 } 59 return Value{ 60 rootValue: rootValue, 61 rootType: TypeOf(rootValue.Type()), 62 } 63 } 64 65 // IsValid returns whether the Value has been initialized with ValueOf. 66 func (v Value) IsValid() bool { 67 return v.rootType != nil 68 } 69 70 // GoValue returns the value that was passed to ValueOf to create v. 71 func (v Value) GoValue() reflect.Value { 72 return v.rootValue 73 } 74 75 // FindMethod returns an object that can be used to make calls on 76 // the given root value to the given root method and object method. 77 // It returns an error if either the root method or the object 78 // method were not found. 79 // It panics if called on the zero Value. 80 func (v Value) FindMethod(rootMethodName string, version int, objMethodName string) (MethodCaller, error) { 81 if !v.IsValid() { 82 panic("FindMethod called on invalid Value") 83 } 84 caller := methodCaller{ 85 rootValue: v.rootValue, 86 } 87 if version != 0 { 88 return nil, &CallNotImplementedError{ 89 RootMethod: rootMethodName, 90 Version: version, 91 } 92 } 93 var err error 94 caller.rootMethod, err = v.rootType.Method(rootMethodName) 95 if err != nil { 96 return nil, &CallNotImplementedError{ 97 RootMethod: rootMethodName, 98 } 99 } 100 caller.objMethod, err = caller.rootMethod.ObjType.Method(objMethodName) 101 if err != nil { 102 return nil, &CallNotImplementedError{ 103 RootMethod: rootMethodName, 104 Method: objMethodName, 105 } 106 } 107 return caller, nil 108 } 109 110 // killer is the same interface as rpc.Killer, but redeclared 111 // here to avoid cyclic dependency. 112 type killer interface { 113 Kill() 114 } 115 116 // Kill implements rpc.Killer.Kill by calling Kill on the root 117 // value if it implements Killer. 118 func (v Value) Kill() { 119 if killer, ok := v.rootValue.Interface().(killer); ok { 120 killer.Kill() 121 } 122 } 123 124 func (caller methodCaller) Call(objId string, arg reflect.Value) (reflect.Value, error) { 125 obj, err := caller.rootMethod.Call(caller.rootValue, objId) 126 if err != nil { 127 return reflect.Value{}, err 128 } 129 return caller.objMethod.Call(obj, arg) 130 } 131 132 func (caller methodCaller) ParamsType() reflect.Type { 133 return caller.objMethod.Params 134 } 135 136 func (caller methodCaller) ResultType() reflect.Type { 137 return caller.objMethod.Result 138 } 139 140 type MethodCaller interface { 141 // ParamsType holds the required type of the parameter to the object method. 142 ParamsType() reflect.Type 143 144 // ResultType holds the result type of the result of calling the object method. 145 ResultType() reflect.Type 146 147 // Call is actually placing a call to instantiate an given instance and 148 // call the method on that instance. 149 Call(objId string, arg reflect.Value) (reflect.Value, error) 150 }