blob: b28e92f9ba8c4d72049f28f97ef8a082aeab8466 [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 "bytes"
21 "encoding/gob"
22 "reflect"
23 "strings"
24)
25
26// IsProtoMessage determines if the specified implements proto.Message type
27func IsProtoMessage(object interface{}) bool {
28 var ok = false
29
30 if object != nil {
31 st := reflect.TypeOf(object)
32 _, ok = st.MethodByName("ProtoMessage")
33 }
34 return ok
35}
36
37// FindOwnerType will traverse a data structure and find the parent type of the specified object
38func FindOwnerType(obj reflect.Value, name string, depth int, found bool) reflect.Type {
Matt Jeanneret384d8c92019-05-06 14:27:31 -040039 prefix := ""
40 for d := 0; d < depth; d++ {
Matt Jeanneretcab955f2019-04-10 15:45:57 -040041 prefix += ">>"
42 }
43 k := obj.Kind()
44 switch k {
45 case reflect.Ptr:
46 if found {
47 return obj.Type()
48 }
49
50 t := obj.Type().Elem()
51 n := reflect.New(t)
52
53 if rc := FindOwnerType(n.Elem(), name, depth+1, found); rc != nil {
54 return rc
55 }
56
57 case reflect.Struct:
58 if found {
59 return obj.Type()
60 }
61
62 for i := 0; i < obj.NumField(); i++ {
63 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
71 if rc := FindOwnerType(obj.Field(i), name, depth+1, found); rc != nil {
72 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
80 for i := 0; i < n.Elem().Len(); i++ {
81 if found {
82 return reflect.ValueOf(n.Elem().Index(i).Interface()).Type()
83 }
84 }
85
86 for i := 0; i < obj.Len(); i++ {
87 if found {
88 return obj.Index(i).Type()
89 }
90
91 if rc := FindOwnerType(obj.Index(i), name, depth+1, found); rc != nil {
92 return rc
93 }
94 }
95 default:
96 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
97 }
98
99 return nil
100}
101
102// FindKeyOwner will traverse a structure to find the owner type of the specified name
103func 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
133 for i := 0; i < n.Elem().Len(); i++ {
134 if rc := FindKeyOwner(n.Elem().Index(i).Interface(), name, depth+1); rc != nil {
135 return rc
136 }
137 }
138 default:
139 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
140 }
141
142 return nil
143}
144
145// GetAttributeValue traverse a structure to find the value of an attribute
146// 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
149func GetAttributeValue(data interface{}, name string, depth int) (string, reflect.Value) {
150 var attribName string
151 var attribValue reflect.Value
152 obj := reflect.ValueOf(data)
153
154 if !obj.IsValid() {
155 return attribName, attribValue
156 }
157
158 k := obj.Kind()
159 switch k {
160 case reflect.Ptr:
161 if obj.IsNil() {
162 return attribName, attribValue
163 }
164
165 if attribName, attribValue = GetAttributeValue(obj.Elem().Interface(), name, depth+1); attribValue.IsValid() {
166 return attribName, attribValue
167 }
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 {
174 return obj.Type().Field(i).Name, obj.Field(i)
175 }
176
177 if obj.Field(i).IsValid() {
178 if attribName, attribValue = GetAttributeValue(obj.Field(i).Interface(), name, depth+1); attribValue.IsValid() {
179 return attribName, attribValue
180 }
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
189 for i := 0; i < obj.Len(); i++ {
190 if attribName, attribValue = GetAttributeValue(obj.Index(i).Interface(), name, depth+1); attribValue.IsValid() {
191 return attribName, attribValue
192 }
193 }
194 default:
195 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
196 }
197
198 return attribName, attribValue
199
200}
201
202// GetAttributeStructure will traverse a structure to find the data structure for the named attribute
203// 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
243 for i := 0; i < obj.Len(); i++ {
244 if rc := GetAttributeStructure(obj.Index(i).Interface(), name, depth+1); rc.Name != "" {
245 return rc
246 }
247
248 }
249 default:
250 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
251 }
252
253 return result
254
255}
256
257func clone2(a interface{}) interface{} {
258 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}
267
268func clone(a, b interface{}) interface{} {
269 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}