blob: 769aa78b780f4517ed30b5a353ddf65743e4eafc [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 "reflect"
21 "strings"
22)
23
Stephane Barbariedc5022d2018-11-19 15:21:44 -050024// IsProtoMessage determines if the specified implements proto.Message type
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040025func IsProtoMessage(object interface{}) bool {
Stephane Barbarie126101e2018-10-11 16:18:48 -040026 var ok = false
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040027
28 if object != nil {
29 st := reflect.TypeOf(object)
30 _, ok = st.MethodByName("ProtoMessage")
31 }
32 return ok
33}
34
Stephane Barbariedc5022d2018-11-19 15:21:44 -050035// FindOwnerType will traverse a data structure and find the parent type of the specified object
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040036func FindOwnerType(obj reflect.Value, name string, depth int, found bool) reflect.Type {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040037 prefix := ""
38 for d := 0; d < depth; d++ {
Stephane Barbarie126101e2018-10-11 16:18:48 -040039 prefix += ">>"
40 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040041 k := obj.Kind()
42 switch k {
43 case reflect.Ptr:
Stephane Barbarie126101e2018-10-11 16:18:48 -040044 if found {
45 return obj.Type()
46 }
47
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040048 t := obj.Type().Elem()
49 n := reflect.New(t)
50
Stephane Barbarie126101e2018-10-11 16:18:48 -040051 if rc := FindOwnerType(n.Elem(), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040052 return rc
53 }
54
55 case reflect.Struct:
Stephane Barbarie126101e2018-10-11 16:18:48 -040056 if found {
57 return obj.Type()
58 }
59
Stephane Barbariedc5022d2018-11-19 15:21:44 -050060 for i := 0; i < obj.NumField(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040061 v := reflect.Indirect(obj)
62
63 json := strings.Split(v.Type().Field(i).Tag.Get("json"), ",")
64
65 if json[0] == name {
66 return FindOwnerType(obj.Field(i), name, depth+1, true)
67 }
68
Stephane Barbarie126101e2018-10-11 16:18:48 -040069 if rc := FindOwnerType(obj.Field(i), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040070 return rc
71 }
72 }
73 case reflect.Slice:
74 s := reflect.MakeSlice(obj.Type(), 1, 1)
75 n := reflect.New(obj.Type())
76 n.Elem().Set(s)
77
Stephane Barbariedc5022d2018-11-19 15:21:44 -050078 for i := 0; i < n.Elem().Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040079 if found {
80 return reflect.ValueOf(n.Elem().Index(i).Interface()).Type()
81 }
82 }
83
Stephane Barbariedc5022d2018-11-19 15:21:44 -050084 for i := 0; i < obj.Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040085 if found {
86 return obj.Index(i).Type()
87 }
88
Stephane Barbarie126101e2018-10-11 16:18:48 -040089 if rc := FindOwnerType(obj.Index(i), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040090 return rc
91 }
92 }
93 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040094 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040095 }
96
97 return nil
98}
99
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500100// FindKeyOwner will traverse a structure to find the owner type of the specified name
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400101func FindKeyOwner(iface interface{}, name string, depth int) interface{} {
102 obj := reflect.ValueOf(iface)
103 k := obj.Kind()
104 switch k {
105 case reflect.Ptr:
106 t := obj.Type().Elem()
107 n := reflect.New(t)
108
109 if rc := FindKeyOwner(n.Elem().Interface(), name, depth+1); rc != nil {
110 return rc
111 }
112
113 case reflect.Struct:
114 for i := 0; i < obj.NumField(); i++ {
115 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
116
117 if json[0] == name {
118 return obj.Type().Field(i).Type
119 }
120
121 if rc := FindKeyOwner(obj.Field(i).Interface(), name, depth+1); rc != nil {
122 return rc
123 }
124 }
125
126 case reflect.Slice:
127 s := reflect.MakeSlice(obj.Type(), 1, 1)
128 n := reflect.New(obj.Type())
129 n.Elem().Set(s)
130
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500131 for i := 0; i < n.Elem().Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400132 if rc := FindKeyOwner(n.Elem().Index(i).Interface(), name, depth+1); rc != nil {
133 return rc
134 }
135 }
136 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400137 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400138 }
139
140 return nil
141}
142
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500143// GetAttributeValue traverse a structure to find the value of an attribute
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400144// FIXME: Need to figure out if GetAttributeValue and GetAttributeStructure can become one
145// Code is repeated in both, but outputs have a different purpose
146// Left as-is for now to get things working
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400147func GetAttributeValue(data interface{}, name string, depth int) (string, reflect.Value) {
148 var attribName string
149 var attribValue reflect.Value
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400150 obj := reflect.ValueOf(data)
151
152 if !obj.IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400153 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400154 }
155
156 k := obj.Kind()
157 switch k {
158 case reflect.Ptr:
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400159 if obj.IsNil() {
160 return attribName, attribValue
161 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400162
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400163 if attribName, attribValue = GetAttributeValue(obj.Elem().Interface(), name, depth+1); attribValue.IsValid() {
164 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400165 }
166
167 case reflect.Struct:
168 for i := 0; i < obj.NumField(); i++ {
169 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
170
171 if json[0] == name {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400172 return obj.Type().Field(i).Name, obj.Field(i)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400173 }
174
175 if obj.Field(i).IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400176 if attribName, attribValue = GetAttributeValue(obj.Field(i).Interface(), name, depth+1); attribValue.IsValid() {
177 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400178 }
179 }
180 }
181
182 case reflect.Slice:
183 s := reflect.MakeSlice(obj.Type(), 1, 1)
184 n := reflect.New(obj.Type())
185 n.Elem().Set(s)
186
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500187 for i := 0; i < obj.Len(); i++ {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400188 if attribName, attribValue = GetAttributeValue(obj.Index(i).Interface(), name, depth+1); attribValue.IsValid() {
189 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400190 }
191 }
192 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400193 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400194 }
195
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400196 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400197
198}
199
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500200// GetAttributeStructure will traverse a structure to find the data structure for the named attribute
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400201// FIXME: See GetAttributeValue(...) comment
202func GetAttributeStructure(data interface{}, name string, depth int) reflect.StructField {
203 var result reflect.StructField
204 obj := reflect.ValueOf(data)
205
206 if !obj.IsValid() {
207 return result
208 }
209
210 k := obj.Kind()
211 switch k {
212 case reflect.Ptr:
213 t := obj.Type().Elem()
214 n := reflect.New(t)
215
216 if rc := GetAttributeStructure(n.Elem().Interface(), name, depth+1); rc.Name != "" {
217 return rc
218 }
219
220 case reflect.Struct:
221 for i := 0; i < obj.NumField(); i++ {
222 v := reflect.Indirect(obj)
223 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
224
225 if json[0] == name {
226 return v.Type().Field(i)
227 }
228
229 if obj.Field(i).IsValid() {
230 if rc := GetAttributeStructure(obj.Field(i).Interface(), name, depth+1); rc.Name != "" {
231 return rc
232 }
233 }
234 }
235
236 case reflect.Slice:
237 s := reflect.MakeSlice(obj.Type(), 1, 1)
238 n := reflect.New(obj.Type())
239 n.Elem().Set(s)
240
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500241 for i := 0; i < obj.Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400242 if rc := GetAttributeStructure(obj.Index(i).Interface(), name, depth+1); rc.Name != "" {
243 return rc
244 }
245
246 }
247 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400248 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400249 }
250
251 return result
252
253}