Merge "mecm-mepm uninstall playbook added"
[ealt-edge.git] / mep / mepserver / mp1 / arch / bus / base.go
1 /*
2  * Copyright 2020 Huawei Technologies Co., Ltd.
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
17 package bus
18
19 import (
20         "fmt"
21         "reflect"
22         "strconv"
23         "strings"
24 )
25
26 type JSONPathInfo struct {
27         ParentNode reflect.Value
28         CurNode    reflect.Value
29         CurName    string
30         e          error
31 }
32
33 type JpErr struct {
34         ErrDes string
35         JPath  string
36 }
37
38 func (e *JpErr) Error() string {
39         return fmt.Sprintf("jpath error info:%s, json path:%s", e.ErrDes, e.JPath)
40 }
41
42 func ObjReflectPath(p reflect.Value, v reflect.Value, path string) JSONPathInfo {
43         fieldName, subPath := GetFirstName(path)
44
45         switch v.Kind() {
46         case reflect.Invalid:
47                 return JSONPathInfo{e: &JpErr{"reflect.Invalid", path}}
48
49         case reflect.Slice, reflect.Array:
50                 return ObjReflectPathArray(v, fieldName, subPath)
51         case reflect.Struct:
52                 return ObjReflectPathStruct(v, fieldName, subPath)
53
54         case reflect.Map:
55                 return ObjReflectPathMap(v, fieldName, subPath)
56
57         case reflect.Ptr:
58                 if v.IsNil() {
59                         return JSONPathInfo{e: &JpErr{"pointer is null", path}}
60                 }
61                 return ObjReflectPath(p, v.Elem(), path)
62         case reflect.Interface:
63                 if v.IsNil() {
64                         return JSONPathInfo{e: &JpErr{"kind is interface, nil", path}}
65                 }
66
67                 if subPath == "" {
68                         return ReflectSafeAddr(v, v.Elem())
69                 }
70                 return ObjReflectPath(p, v.Elem(), path)
71
72         default:
73                 return GetFieldFromPath(p, v, path)
74         }
75 }
76
77 func ObjReflectPathArray(v reflect.Value, fieldName string, subPath string) JSONPathInfo {
78         if fieldName == "-" {
79                 mapInfo := ReflectSafeAddr(v, reflect.ValueOf(nil))
80                 mapInfo.CurName = "-"
81                 return mapInfo
82         }
83
84         idx, err := strconv.Atoi(fieldName)
85         if err != nil {
86                 return JSONPathInfo{e: &JpErr{"Atoi error", fieldName}}
87         }
88         if idx >= v.Len() {
89                 return JSONPathInfo{e: &JpErr{"Index out of range", fieldName}}
90         }
91         if subPath == "" {
92                 return ReflectSafeAddr(v, v.Index(idx))
93         }
94         return ObjReflectPath(v, v.Index(idx), subPath)
95 }
96
97 func ObjReflectPathStruct(v reflect.Value, fieldName string, subPath string) JSONPathInfo {
98
99         vType := v.Type()
100         for i := 0; i < v.NumField(); i++ {
101                 if !MatchJSONFieldName(vType, i, fieldName) {
102                         continue
103                 }
104                 if subPath == "" {
105                         return ReflectSafeAddr(v, v.Field(i))
106                 }
107                 return ObjReflectPath(v, v.Field(i), subPath)
108         }
109         return JSONPathInfo{e: &JpErr{"can not find field in struct", fieldName}}
110
111 }
112
113 func ObjReflectPathMap(v reflect.Value, fieldName string, subPath string) JSONPathInfo {
114         for _, key := range v.MapKeys() {
115                 if ReflectValueToString(key) != fieldName {
116                         continue
117                 }
118
119                 if subPath == "" {
120                         mapInfo := ReflectSafeAddr(v, reflect.ValueOf(nil))
121                         mapInfo.CurName = fieldName
122                         return mapInfo
123                 }
124                 return ObjReflectPath(v, v.MapIndex(key), subPath)
125
126         }
127         if subPath == "" {
128                 mapInfo := ReflectSafeAddr(v, reflect.ValueOf(nil))
129                 mapInfo.CurName = fieldName
130                 return mapInfo
131         }
132
133         return JSONPathInfo{e: &JpErr{"path not in map:" + fieldName, subPath}}
134 }
135
136 func GetFirstName(path string) (string, string) {
137         if len(path) == 0 {
138                 return "", ""
139         }
140         newPath := path
141         if path[0] == '/' {
142                 newPath = path[1:]
143         }
144         pos := strings.IndexByte(newPath, '/')
145         if pos < 0 {
146                 pos = len(newPath)
147         }
148         subPath := newPath[pos:]
149         firstName := newPath[0:pos]
150         escape := strings.IndexByte(firstName, '~')
151         if escape >= 0 {
152                 firstName = strings.Replace(firstName, "~1", "/", -1)
153                 firstName = strings.Replace(firstName, "~0", "~", -1)
154         }
155         return firstName, subPath
156 }
157
158 func MatchJSONFieldName(vType reflect.Type, i int, jsonName string) bool {
159         tag := vType.Field(i).Tag
160         if !strings.Contains(string(tag), jsonName) {
161                 return false
162         }
163         name := tag.Get("json")
164         if name == "" {
165                 name = strings.ToLower(vType.Field(i).Name)
166         } else {
167                 pos := strings.IndexByte(name, ',')
168                 if pos > 0 {
169                         name = name[0:pos]
170                 }
171         }
172         if name == jsonName {
173                 return true
174         }
175
176         return false
177 }
178
179 func GetFieldFromPath(p reflect.Value, v reflect.Value, path string) JSONPathInfo {
180         var info JSONPathInfo
181         if !v.CanAddr() {
182                 return JSONPathInfo{e: &JpErr{"CanAddr false", path}}
183         }
184
185         switch v.Kind() {
186         case reflect.Invalid:
187                 return JSONPathInfo{e: &JpErr{"Kind invalid", path}}
188
189         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
190                 info.ParentNode = p
191                 info.CurNode = v
192                 return info
193
194         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
195                 info.ParentNode = p
196                 info.CurNode = v
197                 return info
198
199         case reflect.Bool:
200                 info.ParentNode = p
201                 info.CurNode = v
202                 return info
203         case reflect.String:
204                 info.ParentNode = p
205                 info.CurNode = v
206                 return info
207         case reflect.Slice, reflect.Map:
208                 info.ParentNode = p
209                 info.CurNode = v
210                 return info
211         case reflect.Ptr:
212                 info.ParentNode = p
213                 info.CurNode = v
214                 return info
215         case reflect.Chan, reflect.Func:
216                 return JSONPathInfo{e: &JpErr{"Kind Chan or Func", path}}
217         default:
218                 return JSONPathInfo{e: &JpErr{"upexpect Kint: reflect.Array, reflect.Struct, reflect.Interface", path}}
219         }
220 }
221
222 func ReflectValueToString(v reflect.Value) string {
223         switch v.Kind() {
224         case reflect.Invalid:
225                 return "invalid"
226         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
227                 return strconv.FormatInt(v.Int(), 10)
228         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
229                 return strconv.FormatUint(v.Uint(), 10)
230         case reflect.Bool:
231                 return strconv.FormatBool(v.Bool())
232         case reflect.String:
233                 return v.String()
234         case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Slice, reflect.Map:
235                 return "invalid"
236         default:
237                 return "invalid"
238         }
239 }
240
241 func ReflectSafeAddr(p reflect.Value, v reflect.Value) JSONPathInfo {
242         var info JSONPathInfo
243
244         if p.CanAddr(){
245                 info.ParentNode = p
246         }
247
248         if v.CanAddr(){
249                 info.CurNode = v
250         }
251         return info
252 }