blob: 4a45741e7ea60a6a0828fd876906b156674b1fcc [file] [log] [blame]
/*
* 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 (
"github.com/apache/servicecomb-service-center/pkg/log"
"github.com/apache/servicecomb-service-center/pkg/plugin"
"github.com/apache/servicecomb-service-center/pkg/util"
"github.com/astaxie/beego"
"sync"
)
var pluginMgr = &PluginManager{}
func init() {
pluginMgr.Initialize()
}
type wrapInstance struct {
dynamic bool
instance PluginInstance
lock sync.RWMutex
}
type PluginManager struct {
plugins map[PluginName]map[string]*Plugin
instances map[PluginName]*wrapInstance
}
func (pm *PluginManager) Initialize() {
pm.plugins = make(map[PluginName]map[string]*Plugin, int(typeEnd))
pm.instances = make(map[PluginName]*wrapInstance, int(typeEnd))
for t := PluginName(0); t != typeEnd; t++ {
pm.instances[t] = &wrapInstance{}
}
}
func (pm *PluginManager) ReloadAll() {
for pn := range pm.instances {
pm.Reload(pn)
}
}
// unsafe
func (pm *PluginManager) Register(p Plugin) {
m, ok := pm.plugins[p.PName]
if !ok {
m = make(map[string]*Plugin, 5)
}
m[p.Name] = &p
pm.plugins[p.PName] = m
log.Infof("load '%s' plugin named '%s'", p.PName, p.Name)
}
func (pm *PluginManager) Get(pn PluginName, name string) *Plugin {
m, ok := pm.plugins[pn]
if !ok {
return nil
}
return m[name]
}
func (pm *PluginManager) Instance(pn PluginName) PluginInstance {
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
}
func (pm *PluginManager) New(pn PluginName) {
var (
title = STATIC
f func() PluginInstance
)
wi := pm.instances[pn]
p := pm.existDynamicPlugin(pn)
if p != nil {
wi.dynamic = true
title = DYNAMIC
f = p.New
} else {
wi.dynamic = false
m, ok := pm.plugins[pn]
if !ok {
return
}
name := beego.AppConfig.DefaultString(pn.String()+"_plugin", BUILDIN)
p, ok = m[name]
if !ok {
return
}
f = p.New
pn.ActiveConfigs().Set(keyPluginName, name)
}
log.Infof("call %s '%s' plugin %s(), new a '%s' instance",
title, p.PName, util.FuncName(f), p.Name)
wi.instance = f()
}
func (pm *PluginManager) Reload(pn PluginName) {
wi := pm.instances[pn]
wi.lock.Lock()
wi.instance = nil
pn.ClearConfigs()
wi.lock.Unlock()
}
func (pm *PluginManager) existDynamicPlugin(pn PluginName) *Plugin {
m, ok := pm.plugins[pn]
if !ok {
return nil
}
// 'buildin' implement of all plugins should call DynamicPluginFunc()
if plugin.PluginLoader().Exist(pn.String()) {
return m[BUILDIN]
}
return nil
}
func Plugins() *PluginManager {
return pluginMgr
}
func RegisterPlugin(p Plugin) {
Plugins().Register(p)
}
func LoadPlugins() {
for t := PluginName(0); t != typeEnd; t++ {
Plugins().Instance(t)
}
}