blob: 250de9c3232564aef7bf92739b602980e7d13269 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -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 */
Stephane Barbariedc5022d2018-11-19 15:21:44 -050016
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040017package model
18
19import (
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040020 desc "github.com/golang/protobuf/descriptor"
21 "github.com/golang/protobuf/proto"
22 "github.com/golang/protobuf/protoc-gen-go/descriptor"
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040023 "github.com/opencord/voltha-go/common/log"
William Kurkiandaa6bb22019-03-07 12:26:28 -050024 "github.com/opencord/voltha-protos/go/common"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040025 "reflect"
26 "strconv"
27 "sync"
28)
29
Stephane Barbarieef6650d2019-07-18 12:15:09 -040030type childTypesSingleton struct {
31 mutex sync.RWMutex
Stephane Barbariedc5022d2018-11-19 15:21:44 -050032 Cache map[interface{}]map[string]*ChildType
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040033}
34
Stephane Barbarieef6650d2019-07-18 12:15:09 -040035var instanceChildTypes *childTypesSingleton
36var onceChildTypes sync.Once
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040037
Stephane Barbarieef6650d2019-07-18 12:15:09 -040038func getChildTypes() *childTypesSingleton {
39 onceChildTypes.Do(func() {
40 instanceChildTypes = &childTypesSingleton{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040041 })
Stephane Barbarieef6650d2019-07-18 12:15:09 -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)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040074}
75
Stephane Barbariedc5022d2018-11-19 15:21:44 -050076// ChildType structure contains construct details of an object
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040077type ChildType struct {
78 ClassModule string
79 ClassType reflect.Type
80 IsContainer bool
81 Key string
82 KeyFromStr func(s string) interface{}
83}
84
Stephane Barbariedc5022d2018-11-19 15:21:44 -050085// ChildrenFields retrieves list of child objects associated to a given interface
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040086func ChildrenFields(cls interface{}) map[string]*ChildType {
87 if cls == nil {
88 return nil
89 }
90 var names map[string]*ChildType
Stephane Barbariedc5022d2018-11-19 15:21:44 -050091 var namesExist bool
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040092
Stephane Barbarieef6650d2019-07-18 12:15:09 -040093 if getChildTypes().Cache == nil {
94 getChildTypes().Cache = make(map[interface{}]map[string]*ChildType)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040095 }
96
97 msgType := reflect.TypeOf(cls)
Stephane Barbarieef6650d2019-07-18 12:15:09 -040098 inst := getChildTypes()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040099
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500100 if names, namesExist = inst.Cache[msgType.String()]; !namesExist {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400101 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)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400111
Stephane Barbarie126101e2018-10-11 16:18:48 -0400112 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() != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400117 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":
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400125 keyFromStr = func(s string) interface{} {
126 i, _ := strconv.Atoi(s)
127 return int32(i)
128 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400129 case "int64":
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400130 keyFromStr = func(s string) interface{} {
131 i, _ := strconv.Atoi(s)
132 return int64(i)
133 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400134 case "uint32":
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400135 keyFromStr = func(s string) interface{} {
136 i, _ := strconv.Atoi(s)
137 return uint32(i)
138 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400139 case "uint64":
140 keyFromStr = func(s string) interface{} {
141 i, _ := strconv.Atoi(s)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400142 return uint64(i)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400143 }
144 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400145 log.Errorf("Key type not implemented - type: %s\n", keyType.(reflect.Type))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400146 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400147 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400148
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
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400158 }
159 }
160 }
161
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400162 getChildTypes().Cache[msgType.String()] = names
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500163 } else {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400164 entry, _ := inst.GetCacheEntry(msgType.String())
165 log.Debugf("Cache entry for %s: %+v", msgType.String(), entry)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400166 }
167
168 return names
169}