pkg/plugin/plugin.go (139 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package plugin import ( "fmt" "sync" "github.com/apache/servicecomb-service-center/pkg/log" "github.com/apache/servicecomb-service-center/pkg/util" ) const ( defaultPluginSize = 20 defaultPluginImplSize = 5 ) var ( globalConfigurator Configurator = &DefaultConfigurator{} pluginMgr = &Manager{} ) func init() { pluginMgr.Initialize() } type wrapInstance struct { dynamic bool instance Instance lock sync.RWMutex } // Manager manages plugin instance generation. // Manager keeps the plugin instance currently used by server // for every plugin interface. type Manager struct { plugins map[Kind]map[ImplName]*Plugin instances map[Kind]*wrapInstance } // Initialize initializes the struct func (pm *Manager) Initialize() { pm.plugins = make(map[Kind]map[ImplName]*Plugin, defaultPluginSize) pm.instances = make(map[Kind]*wrapInstance, defaultPluginSize) } // ReloadAll reloads all the plugin instances func (pm *Manager) ReloadAll() { for pn := range pm.instances { pm.Reload(pn) } } // Register registers a 'Plugin' // unsafe func (pm *Manager) Register(p Plugin) { t := p.Kind m, ok := pm.plugins[t] if !ok { m = make(map[ImplName]*Plugin, defaultPluginImplSize) } m[p.Name] = &p pm.plugins[t] = m pm.instances[t] = &wrapInstance{} log.Info(fmt.Sprintf("load '%s' plugin named '%s'", t, p.Name)) } // Get gets a 'Plugin' func (pm *Manager) Get(pn Kind, name ImplName) *Plugin { m, ok := pm.plugins[pn] if !ok { return nil } return m[name] } // Instance gets an plugin instance. // What plugin instance you get is depended on the supplied go plugin files // (high priority) or the plugin config(low priority) // // The go plugin file should be {plugins_dir}/{Kind}_plugin.so. // ('plugins_dir' must be configured as a valid path in service-center config.) // The plugin config in service-center config should be: // {Kind}_plugin = {ImplName} // // e.g. For registry plugin, you can set a config in app.conf: // plugins_dir = /home, and supply a go plugin file: /home/registry_plugin.so; // or if you want to use etcd as registry, you can set a config in app.conf: // registry_plugin = etcd. func (pm *Manager) Instance(pn Kind) Instance { wi := pm.instances[pn] wi.lock.RLock() if wi.instance != nil { wi.lock.RUnlock() return wi.instance } wi.lock.RUnlock() wi.lock.Lock() if wi.instance != nil { wi.lock.Unlock() return wi.instance } pm.New(pn) wi.lock.Unlock() return wi.instance } // New initializes and sets the instance of a plugin interface, // but not returns it. // Use 'Instance' if you want to get the plugin instance. // We suggest you to use 'Instance' instead of 'New'. func (pm *Manager) New(pn Kind) { var ( title = Static f func() Instance ) wi := pm.instances[pn] p := pm.existDynamicPlugin(pn) if p != nil { // Dynamic plugin has high priority. wi.dynamic = true title = Dynamic f = p.New } else { wi.dynamic = false m, ok := pm.plugins[pn] if !ok { return } name := GetConfigurator().GetImplName(pn) if len(name) == 0 { log.Warn("configurator return plugin implement name is empty") } p, ok = m[ImplName(name)] if !ok { return } f = p.New } log.Info(fmt.Sprintf("call %s '%s' plugin %s(), new a '%s' instance", title, p.Kind, util.FuncName(f), p.Name)) wi.instance = f() } // Reload reloads the instance of the specified plugin interface. func (pm *Manager) Reload(pn Kind) { wi := pm.instances[pn] wi.lock.Lock() wi.instance = nil wi.lock.Unlock() } func (pm *Manager) existDynamicPlugin(pn Kind) *Plugin { m, ok := pm.plugins[pn] if !ok { return nil } // 'buildin' implement of all plugins should call DynamicPluginFunc() if GetLoader().Exist(pn.String()) { return m[Buildin] } return nil } func (pm *Manager) IsDynamicPlugin(pn Kind) bool { wi, ok := Plugins().instances[pn] return ok && wi.dynamic } // Plugins returns the 'Manager'. func Plugins() *Manager { return pluginMgr } // RegisterPlugin registers a 'Plugin'. func RegisterPlugin(p Plugin) { pluginMgr.Register(p) } // LoadPlugins loads and sets all the plugin interfaces's instance. func LoadPlugins() { for p := range pluginMgr.plugins { pluginMgr.Instance(p) } } func GetConfigurator() Configurator { return globalConfigurator } // RegisterConfigurator registers the customize Configurator impl func RegisterConfigurator(cfg Configurator) { globalConfigurator = cfg }