github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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 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 func (caller methodCaller) Call(objId string, arg reflect.Value) (reflect.Value, error) { 111 obj, err := caller.rootMethod.Call(caller.rootValue, objId) 112 if err != nil { 113 return reflect.Value{}, err 114 } 115 return caller.objMethod.Call(obj, arg) 116 } 117 118 func (caller methodCaller) ParamsType() reflect.Type { 119 return caller.objMethod.Params 120 } 121 122 func (caller methodCaller) ResultType() reflect.Type { 123 return caller.objMethod.Result 124 } 125 126 type MethodCaller interface { 127 // ParamsType holds the required type of the parameter to the object method. 128 ParamsType() reflect.Type 129 130 // ResultType holds the result type of the result of calling the object method. 131 ResultType() reflect.Type 132 133 // Call is actually placing a call to instantiate an given instance and 134 // call the method on that instance. 135 Call(objId string, arg reflect.Value) (reflect.Value, error) 136 }