package registry import ( "fmt" "log" "reflect" "runtime" "strings" cda "git.loafle.net/commons_go/di/annotation" cdur "git.loafle.net/commons_go/di/util/reflect" "git.loafle.net/commons_go/logging" ) func init() { registry = newRegistry() } var registry ComponentRegistry type ComponentRegistry interface { RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) RegisterResource(name string, resource interface{}) error GetInstance(t reflect.Type) (interface{}, error) GetInstanceByName(name string) (interface{}, error) } func newRegistry() ComponentRegistry { r := &defaultComponentRegistry{} r.definitionByType = make(map[reflect.Type]*TypeDefinition, 0) r.definitionByName = make(map[string]*TypeDefinition, 0) r.resourceByName = make(map[string]interface{}, 0) return r } type defaultComponentRegistry struct { definitionByType map[reflect.Type]*TypeDefinition definitionByName map[string]*TypeDefinition resourceByName map[string]interface{} } func RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) { pc, _, _, ok := runtime.Caller(1) details := runtime.FuncForPC(pc) if ok && details != nil { log.Printf("called from %s\n", details.Name()) } registry.RegisterType(t, ca) } func (cr *defaultComponentRegistry) RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) { if nil == t { logging.Logger().Panic("DI: t[reflect.Type] is nil") } if !cdur.IsTypeKind(t, reflect.Struct, true) { logging.Logger().Panic(fmt.Sprintf("DI: t[reflect.Type] must be specified but is %v", t)) } td, err := cr.buildDefinition(t) if nil != err { logging.Logger().Panic(fmt.Sprintf("DI: %v", err)) } if _, ok := cr.definitionByType[td.RealType]; ok { logging.Logger().Panic(fmt.Sprintf("DI: The type[%s] of Component is exist already", td.FullName)) } cr.definitionByType[td.RealType] = td name := "" if nil != ca && "" != strings.Trim(ca.Name, " ") { name = ca.Name } else { name = td.TypeName } if eTD, ok := cr.definitionByName[name]; ok { logging.Logger().Panic(fmt.Sprintf("DI: The name[%s] of Component is exist already type[%s]", name, eTD.FullName)) } cr.definitionByName[name] = td } func RegisterResource(name string, resource interface{}) error { return registry.RegisterResource(name, resource) } func (cr *defaultComponentRegistry) RegisterResource(name string, resource interface{}) error { if _, ok := cr.resourceByName[name]; ok { return fmt.Errorf("DI: Resource[%s] is already exist", name) } cr.resourceByName[name] = resource return nil } func GetInstance(t reflect.Type) (interface{}, error) { return registry.GetInstance(t) } func (cr *defaultComponentRegistry) GetInstance(t reflect.Type) (interface{}, error) { if nil == t { return nil, fmt.Errorf("DI: t[reflect.Type] is nil") } var err error rt, _, _ := cdur.GetTypeInfo(t) td, ok := cr.definitionByType[rt] if !ok { td, err = cr.buildDefinition(t) if nil != err { return nil, err } } v := reflect.New(rt) i := v.Interface() for f, fd := range td.Fields { } return nil, nil } func GetInstanceByName(name string) (interface{}, error) { return registry.GetInstanceByName(name) } func (cr *defaultComponentRegistry) GetInstanceByName(name string) (interface{}, error) { return nil, nil } func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*TypeDefinition, error) { if nil == t { return nil, fmt.Errorf("t[reflect.Type] is nil") } rt, pkgName, tName := cdur.GetTypeInfo(t) td := &TypeDefinition{} td.FullName = FullName(pkgName, tName) td.PkgName = pkgName td.TypeName = tName td.Type = t td.RealType = rt nf := rt.NumField() if 0 < nf { fields := make(map[string]*FieldDefinition) for i := 0; i < nf; i++ { f := rt.Field(i) as, err := cda.ParseAnnotation(f.Tag) if nil != err { return nil, err } if nil != as && 0 < len(as) { fRT, fPkgName, fTName := cdur.GetTypeInfo(f.Type) fd := &FieldDefinition{ PkgName: fPkgName, TypeName: fTName, Type: f.Type, RealType: fRT, Annotations: as, } fields[f.Name] = fd } } if 0 < len(fields) { td.Fields = fields } } return td, nil }