267 lines
6.1 KiB
Go
267 lines
6.1 KiB
Go
|
package di
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"reflect"
|
||
|
"strings"
|
||
|
|
||
|
oa "git.loafle.net/overflow/annotation-go"
|
||
|
"git.loafle.net/overflow/di-go/annotation"
|
||
|
our "git.loafle.net/overflow/util-go/reflect"
|
||
|
)
|
||
|
|
||
|
type Registry interface {
|
||
|
RegisterType(t reflect.Type)
|
||
|
RegisterResource(name string, resource interface{}) error
|
||
|
|
||
|
GetInstance(t reflect.Type) (interface{}, error)
|
||
|
GetInstances(ts []reflect.Type) ([]interface{}, error)
|
||
|
GetInstanceByName(name string) (interface{}, error)
|
||
|
GetInstancesByAnnotationType(t reflect.Type) ([]interface{}, error)
|
||
|
}
|
||
|
|
||
|
func New(parent Registry) Registry {
|
||
|
r := &InstanceRegistry{
|
||
|
parent: parent,
|
||
|
definitionByType: make(map[reflect.Type]*TypeDefinition, 0),
|
||
|
definitionByName: make(map[string]*TypeDefinition, 0),
|
||
|
instanceByType: make(map[reflect.Type]interface{}, 0),
|
||
|
instanceByName: make(map[string]interface{}, 0),
|
||
|
}
|
||
|
if nil == r.parent {
|
||
|
r.parent = AppRegistry
|
||
|
}
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
var AppRegistry = &InstanceRegistry{
|
||
|
parent: nil,
|
||
|
definitionByType: make(map[reflect.Type]*TypeDefinition, 0),
|
||
|
definitionByName: make(map[string]*TypeDefinition, 0),
|
||
|
instanceByType: make(map[reflect.Type]interface{}, 0),
|
||
|
instanceByName: make(map[string]interface{}, 0),
|
||
|
}
|
||
|
|
||
|
type InstanceRegistry struct {
|
||
|
parent Registry
|
||
|
definitionByType map[reflect.Type]*TypeDefinition
|
||
|
definitionByName map[string]*TypeDefinition
|
||
|
instanceByType map[reflect.Type]interface{}
|
||
|
instanceByName map[string]interface{}
|
||
|
}
|
||
|
|
||
|
func RegisterType(t reflect.Type) {
|
||
|
AppRegistry.RegisterType(t)
|
||
|
}
|
||
|
func (r *InstanceRegistry) RegisterType(t reflect.Type) {
|
||
|
if nil == t {
|
||
|
log.Panicf("t[reflect.Type] is nil")
|
||
|
}
|
||
|
if !our.IsTypeKind(t, reflect.Struct, true) {
|
||
|
log.Panicf("t[reflect.Type] must be specified but is %v", t)
|
||
|
}
|
||
|
|
||
|
td, err := r.buildDefinition(t)
|
||
|
if nil != err {
|
||
|
log.Panicf("DI: %v", err)
|
||
|
}
|
||
|
|
||
|
if _, ok := r.definitionByType[td.Type]; ok {
|
||
|
log.Panicf("The type[%s] of Component is exist already", td.FullName)
|
||
|
}
|
||
|
r.definitionByType[td.Type] = td
|
||
|
|
||
|
name := td.TypeName
|
||
|
|
||
|
a, err := oa.GetTypeAnnotation(td.Type, annotation.InjectableAnnotationType)
|
||
|
if nil != err {
|
||
|
log.Panicf("%v", err)
|
||
|
}
|
||
|
if nil != a {
|
||
|
ia := a.(*annotation.InjectableAnnotation)
|
||
|
if "" != strings.Trim(ia.Name, " ") {
|
||
|
name = ia.Name
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if eTD, ok := r.definitionByName[name]; ok {
|
||
|
log.Panicf("The name[%s] of Component is exist already type[%s]", name, eTD.FullName)
|
||
|
}
|
||
|
r.definitionByName[name] = td
|
||
|
}
|
||
|
|
||
|
func RegisterResource(name string, resource interface{}) error {
|
||
|
return AppRegistry.RegisterResource(name, resource)
|
||
|
}
|
||
|
func (r *InstanceRegistry) RegisterResource(name string, resource interface{}) error {
|
||
|
if _, ok := r.instanceByName[name]; ok {
|
||
|
return fmt.Errorf("Resource[%s] is already exist", name)
|
||
|
}
|
||
|
r.instanceByName[name] = resource
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *InstanceRegistry) buildDefinition(t reflect.Type) (*TypeDefinition, error) {
|
||
|
if nil == t {
|
||
|
return nil, fmt.Errorf("t[reflect.Type] is nil")
|
||
|
}
|
||
|
|
||
|
rt, pkgName, tName := our.GetTypeInfo(t)
|
||
|
td := &TypeDefinition{}
|
||
|
td.FullName = FullName(pkgName, tName)
|
||
|
td.PkgName = pkgName
|
||
|
td.TypeName = tName
|
||
|
td.Type = t
|
||
|
td.RealType = rt
|
||
|
|
||
|
return td, nil
|
||
|
}
|
||
|
|
||
|
// GetInstance returns instance of type
|
||
|
// t must be pointer of struct
|
||
|
func GetInstance(t reflect.Type) (interface{}, error) {
|
||
|
return AppRegistry.GetInstance(t)
|
||
|
}
|
||
|
func (r *InstanceRegistry) GetInstance(t reflect.Type) (instance interface{}, err error) {
|
||
|
if nil == t {
|
||
|
return nil, fmt.Errorf("t[reflect.Type] is nil")
|
||
|
}
|
||
|
|
||
|
if reflect.Ptr != t.Kind() {
|
||
|
return nil, fmt.Errorf("t[reflect.Type] must be pointer of struct")
|
||
|
}
|
||
|
|
||
|
if reflect.Struct != t.Elem().Kind() {
|
||
|
return nil, fmt.Errorf("t[reflect.Type] must be pointer of struct")
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
td *TypeDefinition
|
||
|
comV interface{}
|
||
|
ok bool
|
||
|
)
|
||
|
|
||
|
rt, _, _ := our.GetTypeInfo(t)
|
||
|
if td, ok = r.definitionByType[t]; !ok {
|
||
|
if td, err = r.buildDefinition(t); nil != err {
|
||
|
return nil, fmt.Errorf("DI: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if comV, ok = r.instanceByType[td.RealType]; ok {
|
||
|
return comV, nil
|
||
|
}
|
||
|
|
||
|
v := reflect.New(rt)
|
||
|
rv := v.Elem()
|
||
|
|
||
|
instance = v.Interface()
|
||
|
r.instanceByType[td.RealType] = instance
|
||
|
err = nil
|
||
|
defer func() {
|
||
|
if nil != err {
|
||
|
instance = nil
|
||
|
delete(r.instanceByType, td.RealType)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
var (
|
||
|
fV interface{}
|
||
|
)
|
||
|
|
||
|
ass, err := oa.GetAllFieldAnnotations(td.Type)
|
||
|
if nil != err {
|
||
|
return nil, fmt.Errorf("%v", err)
|
||
|
}
|
||
|
if nil != ass {
|
||
|
for n, as := range ass {
|
||
|
f := rv.FieldByName(n)
|
||
|
|
||
|
if !f.IsValid() {
|
||
|
err = fmt.Errorf("Field[%s] is not valid", n)
|
||
|
return
|
||
|
}
|
||
|
if !f.CanSet() {
|
||
|
err = fmt.Errorf("Field[%s] can not set", n)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
_, ok = as[annotation.InjectAnnotationType]
|
||
|
if ok {
|
||
|
if fV, err = r.GetInstance(f.Type()); nil != err {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if nil != err {
|
||
|
return
|
||
|
}
|
||
|
f.Set(reflect.ValueOf(fV))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func GetInstanceByName(name string) (interface{}, error) {
|
||
|
return AppRegistry.GetInstanceByName(name)
|
||
|
}
|
||
|
func (r *InstanceRegistry) GetInstanceByName(name string) (interface{}, error) {
|
||
|
v, ok := r.instanceByName[name]
|
||
|
if ok {
|
||
|
return v, nil
|
||
|
}
|
||
|
return nil, fmt.Errorf("Resource[%s] is not exist", name)
|
||
|
}
|
||
|
|
||
|
// GetInstances returns instance of annotated
|
||
|
// n must be name of registered annotation
|
||
|
func GetInstances(ts []reflect.Type) ([]interface{}, error) {
|
||
|
return AppRegistry.GetInstances(ts)
|
||
|
}
|
||
|
func (r *InstanceRegistry) GetInstances(ts []reflect.Type) ([]interface{}, error) {
|
||
|
var (
|
||
|
i interface{}
|
||
|
err error
|
||
|
)
|
||
|
instances := make([]interface{}, 0)
|
||
|
for _, t := range ts {
|
||
|
if i, err = r.GetInstance(t); nil != err {
|
||
|
return nil, err
|
||
|
}
|
||
|
instances = append(instances, i)
|
||
|
}
|
||
|
|
||
|
return instances, nil
|
||
|
}
|
||
|
|
||
|
func GetInstancesByAnnotationType(at reflect.Type) ([]interface{}, error) {
|
||
|
return AppRegistry.GetInstancesByAnnotationType(at)
|
||
|
}
|
||
|
func (r *InstanceRegistry) GetInstancesByAnnotationType(at reflect.Type) ([]interface{}, error) {
|
||
|
var (
|
||
|
a oa.Annotation
|
||
|
i interface{}
|
||
|
err error
|
||
|
)
|
||
|
instances := make([]interface{}, 0)
|
||
|
|
||
|
for _, td := range r.definitionByType {
|
||
|
a, err = oa.GetTypeAnnotation(td.Type, at)
|
||
|
if nil != err {
|
||
|
return nil, err
|
||
|
}
|
||
|
if nil != a {
|
||
|
i, err = r.GetInstance(td.Type)
|
||
|
if nil != err {
|
||
|
return nil, err
|
||
|
}
|
||
|
instances = append(instances, i)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return instances, nil
|
||
|
}
|