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  }