blob: 1a460ed141c48ac61a6bd5918119fae163a91b4d [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 Barbarie4a2564d2018-07-26 11:02:58 -040016package model
17
18import (
19 "bytes"
20 "encoding/gob"
21 "reflect"
22 "strings"
23)
24
25func 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
35func FindOwnerType(obj reflect.Value, name string, depth int, found bool) reflect.Type {
Stephane Barbarie126101e2018-10-11 16:18:48 -040036 prefix := ""
37 for d:=0; d< depth; d++ {
38 prefix += ">>"
39 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040040 k := obj.Kind()
41 switch k {
42 case reflect.Ptr:
Stephane Barbarie126101e2018-10-11 16:18:48 -040043 if found {
44 return obj.Type()
45 }
46
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040047 t := obj.Type().Elem()
48 n := reflect.New(t)
49
Stephane Barbarie126101e2018-10-11 16:18:48 -040050 if rc := FindOwnerType(n.Elem(), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040051 return rc
52 }
53
54 case reflect.Struct:
Stephane Barbarie126101e2018-10-11 16:18:48 -040055 if found {
56 return obj.Type()
57 }
58
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040059 for i := 0; i < obj.NumField(); i += 1 {
60 v := reflect.Indirect(obj)
61
62 json := strings.Split(v.Type().Field(i).Tag.Get("json"), ",")
63
64 if json[0] == name {
65 return FindOwnerType(obj.Field(i), name, depth+1, true)
66 }
67
Stephane Barbarie126101e2018-10-11 16:18:48 -040068 if rc := FindOwnerType(obj.Field(i), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040069 return rc
70 }
71 }
72 case reflect.Slice:
73 s := reflect.MakeSlice(obj.Type(), 1, 1)
74 n := reflect.New(obj.Type())
75 n.Elem().Set(s)
76
77 for i := 0; i < n.Elem().Len(); i += 1 {
78 if found {
79 return reflect.ValueOf(n.Elem().Index(i).Interface()).Type()
80 }
81 }
82
83 for i := 0; i < obj.Len(); i += 1 {
84 if found {
85 return obj.Index(i).Type()
86 }
87
Stephane Barbarie126101e2018-10-11 16:18:48 -040088 if rc := FindOwnerType(obj.Index(i), name, depth+1, found); rc != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040089 return rc
90 }
91 }
92 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040093 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040094 }
95
96 return nil
97}
98
99func FindKeyOwner(iface interface{}, name string, depth int) interface{} {
100 obj := reflect.ValueOf(iface)
101 k := obj.Kind()
102 switch k {
103 case reflect.Ptr:
104 t := obj.Type().Elem()
105 n := reflect.New(t)
106
107 if rc := FindKeyOwner(n.Elem().Interface(), name, depth+1); rc != nil {
108 return rc
109 }
110
111 case reflect.Struct:
112 for i := 0; i < obj.NumField(); i++ {
113 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
114
115 if json[0] == name {
116 return obj.Type().Field(i).Type
117 }
118
119 if rc := FindKeyOwner(obj.Field(i).Interface(), name, depth+1); rc != nil {
120 return rc
121 }
122 }
123
124 case reflect.Slice:
125 s := reflect.MakeSlice(obj.Type(), 1, 1)
126 n := reflect.New(obj.Type())
127 n.Elem().Set(s)
128
129 for i := 0; i < n.Elem().Len(); i += 1 {
130 if rc := FindKeyOwner(n.Elem().Index(i).Interface(), name, depth+1); rc != nil {
131 return rc
132 }
133 }
134 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400135 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400136 }
137
138 return nil
139}
140
141// FIXME: Need to figure out if GetAttributeValue and GetAttributeStructure can become one
142// Code is repeated in both, but outputs have a different purpose
143// Left as-is for now to get things working
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400144func GetAttributeValue(data interface{}, name string, depth int) (string, reflect.Value) {
145 var attribName string
146 var attribValue reflect.Value
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400147 obj := reflect.ValueOf(data)
148
149 if !obj.IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400150 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400151 }
152
153 k := obj.Kind()
154 switch k {
155 case reflect.Ptr:
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400156 if obj.IsNil() {
157 return attribName, attribValue
158 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400159
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400160 if attribName, attribValue = GetAttributeValue(obj.Elem().Interface(), name, depth+1); attribValue.IsValid() {
161 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400162 }
163
164 case reflect.Struct:
165 for i := 0; i < obj.NumField(); i++ {
166 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
167
168 if json[0] == name {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400169 return obj.Type().Field(i).Name, obj.Field(i)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400170 }
171
172 if obj.Field(i).IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400173 if attribName, attribValue = GetAttributeValue(obj.Field(i).Interface(), name, depth+1); attribValue.IsValid() {
174 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400175 }
176 }
177 }
178
179 case reflect.Slice:
180 s := reflect.MakeSlice(obj.Type(), 1, 1)
181 n := reflect.New(obj.Type())
182 n.Elem().Set(s)
183
184 for i := 0; i < obj.Len(); i += 1 {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400185 if attribName, attribValue = GetAttributeValue(obj.Index(i).Interface(), name, depth+1); attribValue.IsValid() {
186 return attribName, attribValue
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400187 }
188 }
189 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400190 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
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
197// FIXME: See GetAttributeValue(...) comment
198func GetAttributeStructure(data interface{}, name string, depth int) reflect.StructField {
199 var result reflect.StructField
200 obj := reflect.ValueOf(data)
201
202 if !obj.IsValid() {
203 return result
204 }
205
206 k := obj.Kind()
207 switch k {
208 case reflect.Ptr:
209 t := obj.Type().Elem()
210 n := reflect.New(t)
211
212 if rc := GetAttributeStructure(n.Elem().Interface(), name, depth+1); rc.Name != "" {
213 return rc
214 }
215
216 case reflect.Struct:
217 for i := 0; i < obj.NumField(); i++ {
218 v := reflect.Indirect(obj)
219 json := strings.Split(obj.Type().Field(i).Tag.Get("json"), ",")
220
221 if json[0] == name {
222 return v.Type().Field(i)
223 }
224
225 if obj.Field(i).IsValid() {
226 if rc := GetAttributeStructure(obj.Field(i).Interface(), name, depth+1); rc.Name != "" {
227 return rc
228 }
229 }
230 }
231
232 case reflect.Slice:
233 s := reflect.MakeSlice(obj.Type(), 1, 1)
234 n := reflect.New(obj.Type())
235 n.Elem().Set(s)
236
237 for i := 0; i < obj.Len(); i += 1 {
238 if rc := GetAttributeStructure(obj.Index(i).Interface(), name, depth+1); rc.Name != "" {
239 return rc
240 }
241
242 }
243 default:
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400244 //log.Debugf("%s Unhandled <%+v> ... It's a %+v\n", prefix, obj, k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400245 }
246
247 return result
248
249}
250
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400251func Clone2(a interface{}) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400252 b := reflect.ValueOf(a)
253 buff := new(bytes.Buffer)
254 enc := gob.NewEncoder(buff)
255 dec := gob.NewDecoder(buff)
256 enc.Encode(a)
257 dec.Decode(b.Elem().Interface())
258
259 return b.Interface()
260}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400261
262func Clone(a, b interface{}) interface{} {
263 buff := new(bytes.Buffer)
264 enc := gob.NewEncoder(buff)
265 dec := gob.NewDecoder(buff)
266 enc.Encode(a)
267 dec.Decode(b)
268 return b
269}