blob: f0fd618302473dbea1c52817b415267ae4dac235 [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 (
20 "bytes"
21 "encoding/gob"
22 "reflect"
23 "strings"
24)
25
Stephane Barbariedc5022d2018-11-19 15:21:44 -050026// IsProtoMessage determines if the specified implements proto.Message type
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040027func IsProtoMessage(object interface{}) bool {
Stephane Barbarie126101e2018-10-11 16:18:48 -040028 var ok = false
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040029
30 if object != nil {
31 st := reflect.TypeOf(object)
32 _, ok = st.MethodByName("ProtoMessage")
33 }
34 return ok
35}
36
Stephane Barbariedc5022d2018-11-19 15:21:44 -050037// FindOwnerType will traverse a data structure and find the parent type of the specified object
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040038func FindOwnerType(obj reflect.Value, name string, depth int, found bool) reflect.Type {
Stephane Barbarie126101e2018-10-11 16:18:48 -040039 prefix := ""
40 for d:=0; d< depth; d++ {
41 prefix += ">>"
42 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040043 k := obj.Kind()
44 switch k {
45 case reflect.Ptr:
Stephane Barbarie126101e2018-10-11 16:18:48 -040046 if found {
47 return obj.Type()
48 }
49
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040050 t := obj.Type().Elem()
51 n := reflect.New(t)
52
Stephane Barbarie126101e2018-10-11 16:18:48 -040053 if rc := FindOwnerType(n.Elem(), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040054 return rc
55 }
56
57 case reflect.Struct:
Stephane Barbarie126101e2018-10-11 16:18:48 -040058 if found {
59 return obj.Type()
60 }
61
Stephane Barbariedc5022d2018-11-19 15:21:44 -050062 for i := 0; i < obj.NumField(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040063 v := reflect.Indirect(obj)
64
65 json := strings.Split(v.Type().Field(i).Tag.Get("json"), ",")
66
67 if json[0] == name {
68 return FindOwnerType(obj.Field(i), name, depth+1, true)
69 }
70
Stephane Barbarie126101e2018-10-11 16:18:48 -040071 if rc := FindOwnerType(obj.Field(i), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040072 return rc
73 }
74 }
75 case reflect.Slice:
76 s := reflect.MakeSlice(obj.Type(), 1, 1)
77 n := reflect.New(obj.Type())
78 n.Elem().Set(s)
79
Stephane Barbariedc5022d2018-11-19 15:21:44 -050080 for i := 0; i < n.Elem().Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040081 if found {
82 return reflect.ValueOf(n.Elem().Index(i).Interface()).Type()
83 }
84 }
85
Stephane Barbariedc5022d2018-11-19 15:21:44 -050086 for i := 0; i < obj.Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040087 if found {
88 return obj.Index(i).Type()
89 }
90
Stephane Barbarie126101e2018-10-11 16:18:48 -040091 if rc := FindOwnerType(obj.Index(i), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040092 return rc
93 }
94 }
95 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040096 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040097 }
98
99 return nil
100}
101
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500102// FindKeyOwner will traverse a structure to find the owner type of the specified name
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400103func FindKeyOwner(iface interface{}, name string, depth int) interface{} {
104 obj := reflect.ValueOf(iface)
105 k := obj.Kind()
106 switch k {
107 case reflect.Ptr:
108 t := obj.Type().Elem()
109 n := reflect.New(t)
110
111 if rc := FindKeyOwner(n.Elem().Interface(), name, depth+1); rc != nil {
112 return rc
113 }
114
115 case reflect.Struct:
116 for i := 0; i < obj.NumField(); i++ {
117 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
118
119 if json[0] == name {
120 return obj.Type().Field(i).Type
121 }
122
123 if rc := FindKeyOwner(obj.Field(i).Interface(), name, depth+1); rc != nil {
124 return rc
125 }
126 }
127
128 case reflect.Slice:
129 s := reflect.MakeSlice(obj.Type(), 1, 1)
130 n := reflect.New(obj.Type())
131 n.Elem().Set(s)
132
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500133 for i := 0; i < n.Elem().Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400134 if rc := FindKeyOwner(n.Elem().Index(i).Interface(), name, depth+1); rc != nil {
135 return rc
136 }
137 }
138 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400139 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400140 }
141
142 return nil
143}
144
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500145// GetAttributeValue traverse a structure to find the value of an attribute
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400146// FIXME: Need to figure out if GetAttributeValue and GetAttributeStructure can become one
147// Code is repeated in both, but outputs have a different purpose
148// Left as-is for now to get things working
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400149func GetAttributeValue(data interface{}, name string, depth int) (string, reflect.Value) {
150 var attribName string
151 var attribValue reflect.Value
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400152 obj := reflect.ValueOf(data)
153
154 if !obj.IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400155 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400156 }
157
158 k := obj.Kind()
159 switch k {
160 case reflect.Ptr:
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400161 if obj.IsNil() {
162 return attribName, attribValue
163 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400164
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400165 if attribName, attribValue = GetAttributeValue(obj.Elem().Interface(), name, depth+1); attribValue.IsValid() {
166 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400167 }
168
169 case reflect.Struct:
170 for i := 0; i < obj.NumField(); i++ {
171 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
172
173 if json[0] == name {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400174 return obj.Type().Field(i).Name, obj.Field(i)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400175 }
176
177 if obj.Field(i).IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400178 if attribName, attribValue = GetAttributeValue(obj.Field(i).Interface(), name, depth+1); attribValue.IsValid() {
179 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400180 }
181 }
182 }
183
184 case reflect.Slice:
185 s := reflect.MakeSlice(obj.Type(), 1, 1)
186 n := reflect.New(obj.Type())
187 n.Elem().Set(s)
188
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500189 for i := 0; i < obj.Len(); i++ {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400190 if attribName, attribValue = GetAttributeValue(obj.Index(i).Interface(), name, depth+1); attribValue.IsValid() {
191 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400192 }
193 }
194 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400195 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400196 }
197
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400198 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400199
200}
201
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500202// GetAttributeStructure will traverse a structure to find the data structure for the named attribute
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400203// FIXME: See GetAttributeValue(...) comment
204func GetAttributeStructure(data interface{}, name string, depth int) reflect.StructField {
205 var result reflect.StructField
206 obj := reflect.ValueOf(data)
207
208 if !obj.IsValid() {
209 return result
210 }
211
212 k := obj.Kind()
213 switch k {
214 case reflect.Ptr:
215 t := obj.Type().Elem()
216 n := reflect.New(t)
217
218 if rc := GetAttributeStructure(n.Elem().Interface(), name, depth+1); rc.Name != "" {
219 return rc
220 }
221
222 case reflect.Struct:
223 for i := 0; i < obj.NumField(); i++ {
224 v := reflect.Indirect(obj)
225 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
226
227 if json[0] == name {
228 return v.Type().Field(i)
229 }
230
231 if obj.Field(i).IsValid() {
232 if rc := GetAttributeStructure(obj.Field(i).Interface(), name, depth+1); rc.Name != "" {
233 return rc
234 }
235 }
236 }
237
238 case reflect.Slice:
239 s := reflect.MakeSlice(obj.Type(), 1, 1)
240 n := reflect.New(obj.Type())
241 n.Elem().Set(s)
242
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500243 for i := 0; i < obj.Len(); i++ {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400244 if rc := GetAttributeStructure(obj.Index(i).Interface(), name, depth+1); rc.Name != "" {
245 return rc
246 }
247
248 }
249 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400250 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400251 }
252
253 return result
254
255}
256
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500257func clone2(a interface{}) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400258 b := reflect.ValueOf(a)
259 buff := new(bytes.Buffer)
260 enc := gob.NewEncoder(buff)
261 dec := gob.NewDecoder(buff)
262 enc.Encode(a)
263 dec.Decode(b.Elem().Interface())
264
265 return b.Interface()
266}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400267
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500268func clone(a, b interface{}) interface{} {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400269 buff := new(bytes.Buffer)
270 enc := gob.NewEncoder(buff)
271 dec := gob.NewDecoder(buff)
272 enc.Encode(a)
273 dec.Decode(b)
274 return b
275}