github.com/kaituanwang/hyperledger@v2.0.1+incompatible/core/handlers/library/registry.go (about)

     1  /*
     2  Copyright IBM Corp, SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package library
     8  
     9  import (
    10  	"fmt"
    11  	"os"
    12  	"plugin"
    13  	"reflect"
    14  	"sync"
    15  
    16  	"github.com/hyperledger/fabric/common/flogging"
    17  	"github.com/hyperledger/fabric/core/handlers/auth"
    18  	"github.com/hyperledger/fabric/core/handlers/decoration"
    19  	endorsement2 "github.com/hyperledger/fabric/core/handlers/endorsement/api"
    20  	validation "github.com/hyperledger/fabric/core/handlers/validation/api"
    21  )
    22  
    23  var logger = flogging.MustGetLogger("core.handlers")
    24  
    25  // Registry defines an object that looks up
    26  // handlers by name
    27  type Registry interface {
    28  	// Lookup returns a handler with a given
    29  	// registered name, or nil if does not exist
    30  	Lookup(HandlerType) interface{}
    31  }
    32  
    33  // HandlerType defines custom handlers that can filter and mutate
    34  // objects passing within the peer
    35  type HandlerType int
    36  
    37  const (
    38  	// Auth handler - reject or forward proposals from clients
    39  	Auth HandlerType = iota
    40  	// Decoration handler - append or mutate the chaincode input
    41  	// passed to the chaincode
    42  	Decoration
    43  	Endorsement
    44  	Validation
    45  
    46  	authPluginFactory      = "NewFilter"
    47  	decoratorPluginFactory = "NewDecorator"
    48  	pluginFactory          = "NewPluginFactory"
    49  )
    50  
    51  type registry struct {
    52  	filters    []auth.Filter
    53  	decorators []decoration.Decorator
    54  	endorsers  map[string]endorsement2.PluginFactory
    55  	validators map[string]validation.PluginFactory
    56  }
    57  
    58  var once sync.Once
    59  var reg registry
    60  
    61  // InitRegistry creates the (only) instance
    62  // of the registry
    63  func InitRegistry(c Config) Registry {
    64  	once.Do(func() {
    65  		reg = registry{
    66  			endorsers:  make(map[string]endorsement2.PluginFactory),
    67  			validators: make(map[string]validation.PluginFactory),
    68  		}
    69  		reg.loadHandlers(c)
    70  	})
    71  	return &reg
    72  }
    73  
    74  // loadHandlers loads the configured handlers
    75  func (r *registry) loadHandlers(c Config) {
    76  	for _, config := range c.AuthFilters {
    77  		r.evaluateModeAndLoad(config, Auth)
    78  	}
    79  	for _, config := range c.Decorators {
    80  		r.evaluateModeAndLoad(config, Decoration)
    81  	}
    82  
    83  	for chaincodeID, config := range c.Endorsers {
    84  		r.evaluateModeAndLoad(config, Endorsement, chaincodeID)
    85  	}
    86  
    87  	for chaincodeID, config := range c.Validators {
    88  		r.evaluateModeAndLoad(config, Validation, chaincodeID)
    89  	}
    90  }
    91  
    92  // evaluateModeAndLoad if a library path is provided, load the shared object
    93  func (r *registry) evaluateModeAndLoad(c *HandlerConfig, handlerType HandlerType, extraArgs ...string) {
    94  	if c.Library != "" {
    95  		r.loadPlugin(c.Library, handlerType, extraArgs...)
    96  	} else {
    97  		r.loadCompiled(c.Name, handlerType, extraArgs...)
    98  	}
    99  }
   100  
   101  // loadCompiled loads a statically compiled handler
   102  func (r *registry) loadCompiled(handlerFactory string, handlerType HandlerType, extraArgs ...string) {
   103  	registryMD := reflect.ValueOf(&HandlerLibrary{})
   104  
   105  	o := registryMD.MethodByName(handlerFactory)
   106  	if !o.IsValid() {
   107  		logger.Panicf(fmt.Sprintf("Method %s isn't a method of HandlerLibrary", handlerFactory))
   108  	}
   109  
   110  	inst := o.Call(nil)[0].Interface()
   111  
   112  	if handlerType == Auth {
   113  		r.filters = append(r.filters, inst.(auth.Filter))
   114  	} else if handlerType == Decoration {
   115  		r.decorators = append(r.decorators, inst.(decoration.Decorator))
   116  	} else if handlerType == Endorsement {
   117  		if len(extraArgs) != 1 {
   118  			logger.Panicf("expected 1 argument in extraArgs")
   119  		}
   120  		r.endorsers[extraArgs[0]] = inst.(endorsement2.PluginFactory)
   121  	} else if handlerType == Validation {
   122  		if len(extraArgs) != 1 {
   123  			logger.Panicf("expected 1 argument in extraArgs")
   124  		}
   125  		r.validators[extraArgs[0]] = inst.(validation.PluginFactory)
   126  	}
   127  }
   128  
   129  // loadPlugin loads a pluggable handler
   130  func (r *registry) loadPlugin(pluginPath string, handlerType HandlerType, extraArgs ...string) {
   131  	if _, err := os.Stat(pluginPath); err != nil {
   132  		logger.Panicf(fmt.Sprintf("Could not find plugin at path %s: %s", pluginPath, err))
   133  	}
   134  	p, err := plugin.Open(pluginPath)
   135  	if err != nil {
   136  		logger.Panicf(fmt.Sprintf("Error opening plugin at path %s: %s", pluginPath, err))
   137  	}
   138  
   139  	if handlerType == Auth {
   140  		r.initAuthPlugin(p)
   141  	} else if handlerType == Decoration {
   142  		r.initDecoratorPlugin(p)
   143  	} else if handlerType == Endorsement {
   144  		r.initEndorsementPlugin(p, extraArgs...)
   145  	} else if handlerType == Validation {
   146  		r.initValidationPlugin(p, extraArgs...)
   147  	}
   148  }
   149  
   150  // initAuthPlugin constructs an auth filter from the given plugin
   151  func (r *registry) initAuthPlugin(p *plugin.Plugin) {
   152  	constructorSymbol, err := p.Lookup(authPluginFactory)
   153  	if err != nil {
   154  		panicWithLookupError(authPluginFactory, err)
   155  	}
   156  	constructor, ok := constructorSymbol.(func() auth.Filter)
   157  	if !ok {
   158  		panicWithDefinitionError(authPluginFactory)
   159  	}
   160  
   161  	filter := constructor()
   162  	if filter != nil {
   163  		r.filters = append(r.filters, filter)
   164  	}
   165  }
   166  
   167  // initDecoratorPlugin constructs a decorator from the given plugin
   168  func (r *registry) initDecoratorPlugin(p *plugin.Plugin) {
   169  	constructorSymbol, err := p.Lookup(decoratorPluginFactory)
   170  	if err != nil {
   171  		panicWithLookupError(decoratorPluginFactory, err)
   172  	}
   173  	constructor, ok := constructorSymbol.(func() decoration.Decorator)
   174  	if !ok {
   175  		panicWithDefinitionError(decoratorPluginFactory)
   176  	}
   177  	decorator := constructor()
   178  	if decorator != nil {
   179  		r.decorators = append(r.decorators, constructor())
   180  	}
   181  }
   182  
   183  func (r *registry) initEndorsementPlugin(p *plugin.Plugin, extraArgs ...string) {
   184  	if len(extraArgs) != 1 {
   185  		logger.Panicf("expected 1 argument in extraArgs")
   186  	}
   187  	factorySymbol, err := p.Lookup(pluginFactory)
   188  	if err != nil {
   189  		panicWithLookupError(pluginFactory, err)
   190  	}
   191  
   192  	constructor, ok := factorySymbol.(func() endorsement2.PluginFactory)
   193  	if !ok {
   194  		panicWithDefinitionError(pluginFactory)
   195  	}
   196  	factory := constructor()
   197  	if factory == nil {
   198  		logger.Panicf("factory instance returned nil")
   199  	}
   200  	r.endorsers[extraArgs[0]] = factory
   201  }
   202  
   203  func (r *registry) initValidationPlugin(p *plugin.Plugin, extraArgs ...string) {
   204  	if len(extraArgs) != 1 {
   205  		logger.Panicf("expected 1 argument in extraArgs")
   206  	}
   207  	factorySymbol, err := p.Lookup(pluginFactory)
   208  	if err != nil {
   209  		panicWithLookupError(pluginFactory, err)
   210  	}
   211  
   212  	constructor, ok := factorySymbol.(func() validation.PluginFactory)
   213  	if !ok {
   214  		panicWithDefinitionError(pluginFactory)
   215  	}
   216  	factory := constructor()
   217  	if factory == nil {
   218  		logger.Panicf("factory instance returned nil")
   219  	}
   220  	r.validators[extraArgs[0]] = factory
   221  }
   222  
   223  // panicWithLookupError panics when a handler constructor lookup fails
   224  func panicWithLookupError(factory string, err error) {
   225  	logger.Panicf(fmt.Sprintf("Plugin must contain constructor with name %s. Error from lookup: %s",
   226  		factory, err))
   227  }
   228  
   229  // panicWithDefinitionError panics when a handler constructor does not match
   230  // the expected function definition
   231  func panicWithDefinitionError(factory string) {
   232  	logger.Panicf(fmt.Sprintf("Constructor method %s does not match expected definition",
   233  		factory))
   234  }
   235  
   236  // Lookup returns a list of handlers with the given
   237  // type, or nil if none exist
   238  func (r *registry) Lookup(handlerType HandlerType) interface{} {
   239  	if handlerType == Auth {
   240  		return r.filters
   241  	} else if handlerType == Decoration {
   242  		return r.decorators
   243  	} else if handlerType == Endorsement {
   244  		return r.endorsers
   245  	} else if handlerType == Validation {
   246  		return r.validators
   247  	}
   248  
   249  	return nil
   250  }