blob: fae98444b09520ab15855e873cc0db5df30c9ad4 [file] [log] [blame]
Matt Jeanneretcab955f2019-04-10 15:45:57 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package model
18
19import (
20 desc "github.com/golang/protobuf/descriptor"
21 "github.com/golang/protobuf/proto"
22 "github.com/golang/protobuf/protoc-gen-go/descriptor"
Scott Bakerf8424cc2019-10-18 11:26:50 -070023 "github.com/opencord/voltha-lib-go/pkg/log"
Matt Jeanneretcab955f2019-04-10 15:45:57 -040024 "github.com/opencord/voltha-protos/go/common"
25 "reflect"
26 "strconv"
27 "sync"
28)
29
Manikkaraj kb1d51442019-07-23 10:41:02 -040030type childTypesSingleton struct {
31 mutex sync.RWMutex
Matt Jeanneretcab955f2019-04-10 15:45:57 -040032 Cache map[interface{}]map[string]*ChildType
33}
34
Manikkaraj kb1d51442019-07-23 10:41:02 -040035var instanceChildTypes *childTypesSingleton
36var onceChildTypes sync.Once
Matt Jeanneretcab955f2019-04-10 15:45:57 -040037
Manikkaraj kb1d51442019-07-23 10:41:02 -040038func getChildTypes() *childTypesSingleton {
39 onceChildTypes.Do(func() {
40 instanceChildTypes = &childTypesSingleton{}
Matt Jeanneretcab955f2019-04-10 15:45:57 -040041 })
Manikkaraj kb1d51442019-07-23 10:41:02 -040042 return instanceChildTypes
43}
44
45func (s *childTypesSingleton) GetCache() map[interface{}]map[string]*ChildType {
46 s.mutex.RLock()
47 defer s.mutex.RUnlock()
48 return s.Cache
49}
50
51func (s *childTypesSingleton) SetCache(cache map[interface{}]map[string]*ChildType) {
52 s.mutex.Lock()
53 defer s.mutex.Unlock()
54 s.Cache = cache
55}
56
57func (s *childTypesSingleton) GetCacheEntry(key interface{}) (map[string]*ChildType, bool) {
58 s.mutex.RLock()
59 defer s.mutex.RUnlock()
60 childTypeMap, exists := s.Cache[key]
61 return childTypeMap, exists
62}
63
64func (s *childTypesSingleton) SetCacheEntry(key interface{}, value map[string]*ChildType) {
65 s.mutex.Lock()
66 defer s.mutex.Unlock()
67 s.Cache[key] = value
68}
69
70func (s *childTypesSingleton) ResetCache() {
71 s.mutex.Lock()
72 defer s.mutex.Unlock()
73 s.Cache = make(map[interface{}]map[string]*ChildType)
Matt Jeanneretcab955f2019-04-10 15:45:57 -040074}
75
76// ChildType structure contains construct details of an object
77type ChildType struct {
78 ClassModule string
79 ClassType reflect.Type
80 IsContainer bool
81 Key string
82 KeyFromStr func(s string) interface{}
83}
84
85// ChildrenFields retrieves list of child objects associated to a given interface
86func ChildrenFields(cls interface{}) map[string]*ChildType {
87 if cls == nil {
88 return nil
89 }
90 var names map[string]*ChildType
91 var namesExist bool
92
Manikkaraj kb1d51442019-07-23 10:41:02 -040093 if getChildTypes().Cache == nil {
94 getChildTypes().Cache = make(map[interface{}]map[string]*ChildType)
Matt Jeanneretcab955f2019-04-10 15:45:57 -040095 }
96
97 msgType := reflect.TypeOf(cls)
Manikkaraj kb1d51442019-07-23 10:41:02 -040098 inst := getChildTypes()
Matt Jeanneretcab955f2019-04-10 15:45:57 -040099
100 if names, namesExist = inst.Cache[msgType.String()]; !namesExist {
101 names = make(map[string]*ChildType)
102
103 _, md := desc.ForMessage(cls.(desc.Message))
104
105 // TODO: Do we need to validate MD for nil, panic or exception?
106 for _, field := range md.Field {
107 if options := field.GetOptions(); options != nil {
108 if proto.HasExtension(options, common.E_ChildNode) {
109 isContainer := *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
110 meta, _ := proto.GetExtension(options, common.E_ChildNode)
111
112 var keyFromStr func(string) interface{}
113 var ct ChildType
114
115 parentType := FindOwnerType(reflect.ValueOf(cls), field.GetName(), 0, false)
116 if meta.(*common.ChildNode).GetKey() != "" {
117 keyType := FindKeyOwner(reflect.New(parentType).Elem().Interface(), meta.(*common.ChildNode).GetKey(), 0)
118
119 switch keyType.(reflect.Type).Name() {
120 case "string":
121 keyFromStr = func(s string) interface{} {
122 return s
123 }
124 case "int32":
125 keyFromStr = func(s string) interface{} {
126 i, _ := strconv.Atoi(s)
127 return int32(i)
128 }
129 case "int64":
130 keyFromStr = func(s string) interface{} {
131 i, _ := strconv.Atoi(s)
132 return int64(i)
133 }
134 case "uint32":
135 keyFromStr = func(s string) interface{} {
136 i, _ := strconv.Atoi(s)
137 return uint32(i)
138 }
139 case "uint64":
140 keyFromStr = func(s string) interface{} {
141 i, _ := strconv.Atoi(s)
142 return uint64(i)
143 }
144 default:
145 log.Errorf("Key type not implemented - type: %s\n", keyType.(reflect.Type))
146 }
147 }
148
149 ct = ChildType{
150 ClassModule: parentType.String(),
151 ClassType: parentType,
152 IsContainer: isContainer,
153 Key: meta.(*common.ChildNode).GetKey(),
154 KeyFromStr: keyFromStr,
155 }
156
157 names[field.GetName()] = &ct
158 }
159 }
160 }
161
Manikkaraj kb1d51442019-07-23 10:41:02 -0400162 getChildTypes().Cache[msgType.String()] = names
Matt Jeanneretcab955f2019-04-10 15:45:57 -0400163 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400164 entry, _ := inst.GetCacheEntry(msgType.String())
165 log.Debugf("Cache entry for %s: %+v", msgType.String(), entry)
Matt Jeanneretcab955f2019-04-10 15:45:57 -0400166 }
167
168 return names
169}