blob: 73f79a3d0d8422c1cdc9a70d250b4456f22f2fd8 [file] [log] [blame]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -04001package model
2
3import (
4 "fmt"
5 desc "github.com/golang/protobuf/descriptor"
6 "github.com/golang/protobuf/proto"
7 "github.com/golang/protobuf/protoc-gen-go/descriptor"
8 "github.com/opencord/voltha/protos/go/common"
9 "reflect"
10 "strconv"
11 "sync"
12)
13
14type singleton struct {
15 ChildrenFieldsCache map[interface{}]map[string]*ChildType
16}
17
18var instance *singleton
19var once sync.Once
20
21func GetInstance() *singleton {
22 once.Do(func() {
23 instance = &singleton{}
24 })
25 return instance
26}
27
28type ChildType struct {
29 ClassModule string
30 ClassType reflect.Type
31 IsContainer bool
32 Key string
33 KeyFromStr func(s string) interface{}
34}
35
36func ChildrenFields(cls interface{}) map[string]*ChildType {
37 if cls == nil {
38 return nil
39 }
40 var names map[string]*ChildType
41 var names_exist bool
42
43 if GetInstance().ChildrenFieldsCache == nil {
44 GetInstance().ChildrenFieldsCache = make(map[interface{}]map[string]*ChildType)
45 }
46
47 msgType := reflect.TypeOf(cls)
48
49 if names, names_exist = GetInstance().ChildrenFieldsCache[msgType.String()]; !names_exist {
50 names = make(map[string]*ChildType)
51
52 _, md := desc.ForMessage(cls.(desc.Message))
53
54 // TODO: Do we need to validate MD for nil, panic or exception?
55 for _, field := range md.Field {
56 if options := field.GetOptions(); options != nil {
57 if proto.HasExtension(options, common.E_ChildNode) {
58 isContainer := *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
59 meta, _ := proto.GetExtension(options, common.E_ChildNode)
60 var keyFromStr func(string) interface{}
61
62 if meta.(*common.ChildNode).GetKey() == "" {
63 fmt.Println("Child key is empty ... moving on")
64 } else {
65 parentType := FindOwnerType(reflect.ValueOf(cls), field.GetName(), 0, false)
66 keyType := FindKeyOwner(reflect.New(parentType).Elem().Interface(), meta.(*common.ChildNode).GetKey(), 0)
67
68 switch keyType.(reflect.Type).Name() {
69 case "string":
70 keyFromStr = func(s string) interface{} {
71 return s
72 }
73 case "int32":
74 fallthrough
75 case "int64":
76 fallthrough
77 case "uint32":
78 fallthrough
79 case "uint64":
80 keyFromStr = func(s string) interface{} {
81 i, _ := strconv.Atoi(s)
82 return i
83 }
84 default:
85 fmt.Errorf("Key type not implemented - type: %s\n", keyType.(reflect.Type))
86 }
87
88 ct := ChildType{
89 ClassModule: parentType.String(),
90 ClassType: parentType,
91 IsContainer: isContainer,
92 Key: meta.(*common.ChildNode).GetKey(),
93 KeyFromStr: keyFromStr,
94 }
95
96 names[field.GetName()] = &ct
97
98 }
99 }
100 }
101 }
102
103 GetInstance().ChildrenFieldsCache[msgType.String()] = names
104 }
105
106 return names
107}