blob: 6d1b2d5d440d69bd9d355392241707db1a05bdae [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 Barbarie4a2564d2018-07-26 11:02:58 -040094 }
95
96 return nil
97}
98
Stephane Barbariedc5022d2018-11-19 15:21:44 -050099// FindKeyOwner will traverse a structure to find the owner type of the specified name
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400100func FindKeyOwner(iface interface{}, name string, depth int) interface{} {
101 obj := reflect.ValueOf(iface)
102 k := obj.Kind()
103 switch k {
104 case reflect.Ptr:
105 t := obj.Type().Elem()
106 n := reflect.New(t)
107
108 if rc := FindKeyOwner(n.Elem().Interface(), name, depth+1); rc != nil {
109 return rc
110 }
111
112 case reflect.Struct:
113 for i := 0; i < obj.NumField(); i++ {
114 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
115
116 if json[0] == name {
117 return obj.Type().Field(i).Type
118 }
119
120 if rc := FindKeyOwner(obj.Field(i).Interface(), name, depth+1); rc != nil {
121 return rc
122 }
123 }
124
125 case reflect.Slice:
126 s := reflect.MakeSlice(obj.Type(), 1, 1)
127 n := reflect.New(obj.Type())
128 n.Elem().Set(s)
129
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500130 for i := 0; i < n.Elem().Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400131 if rc := FindKeyOwner(n.Elem().Index(i).Interface(), name, depth+1); rc != nil {
132 return rc
133 }
134 }
135 default:
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400136 }
137
138 return nil
139}
140
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500141// GetAttributeValue traverse a structure to find the value of an attribute
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400142// FIXME: Need to figure out if GetAttributeValue and GetAttributeStructure can become one
143// Code is repeated in both, but outputs have a different purpose
144// Left as-is for now to get things working
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400145func GetAttributeValue(data interface{}, name string, depth int) (string, reflect.Value) {
146 var attribName string
147 var attribValue reflect.Value
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400148 obj := reflect.ValueOf(data)
149
150 if !obj.IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400151 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400152 }
153
154 k := obj.Kind()
155 switch k {
156 case reflect.Ptr:
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400157 if obj.IsNil() {
158 return attribName, attribValue
159 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400160
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400161 if attribName, attribValue = GetAttributeValue(obj.Elem().Interface(), name, depth+1); attribValue.IsValid() {
162 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400163 }
164
165 case reflect.Struct:
166 for i := 0; i < obj.NumField(); i++ {
167 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
168
169 if json[0] == name {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400170 return obj.Type().Field(i).Name, obj.Field(i)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400171 }
172
173 if obj.Field(i).IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400174 if attribName, attribValue = GetAttributeValue(obj.Field(i).Interface(), name, depth+1); attribValue.IsValid() {
175 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400176 }
177 }
178 }
179
180 case reflect.Slice:
181 s := reflect.MakeSlice(obj.Type(), 1, 1)
182 n := reflect.New(obj.Type())
183 n.Elem().Set(s)
184
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500185 for i := 0; i < obj.Len(); i++ {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400186 if attribName, attribValue = GetAttributeValue(obj.Index(i).Interface(), name, depth+1); attribValue.IsValid() {
187 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400188 }
189 }
190 default:
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400191 }
192
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400193 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400194
195}
196
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500197// GetAttributeStructure will traverse a structure to find the data structure for the named attribute
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400198// FIXME: See GetAttributeValue(...) comment
199func GetAttributeStructure(data interface{}, name string, depth int) reflect.StructField {
200 var result reflect.StructField
201 obj := reflect.ValueOf(data)
202
203 if !obj.IsValid() {
204 return result
205 }
206
207 k := obj.Kind()
208 switch k {
209 case reflect.Ptr:
210 t := obj.Type().Elem()
211 n := reflect.New(t)
212
213 if rc := GetAttributeStructure(n.Elem().Interface(), name, depth+1); rc.Name != "" {
214 return rc
215 }
216
217 case reflect.Struct:
218 for i := 0; i < obj.NumField(); i++ {
219 v := reflect.Indirect(obj)
220 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
221
222 if json[0] == name {
223 return v.Type().Field(i)
224 }
225
226 if obj.Field(i).IsValid() {
227 if rc := GetAttributeStructure(obj.Field(i).Interface(), name, depth+1); rc.Name != "" {
228 return rc
229 }
230 }
231 }
232
233 case reflect.Slice:
234 s := reflect.MakeSlice(obj.Type(), 1, 1)
235 n := reflect.New(obj.Type())
236 n.Elem().Set(s)
237
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500238 for i := 0; i < obj.Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400239 if rc := GetAttributeStructure(obj.Index(i).Interface(), name, depth+1); rc.Name != "" {
240 return rc
241 }
242
243 }
244 default:
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400245 }
246
247 return result
248
249}