github.com/whatap/golib@v0.0.22/util/pathutil/PathTree.go (about) 1 package pathutil 2 3 import ( 4 "container/list" 5 "fmt" 6 "strings" 7 "sync" 8 ) 9 10 const ( 11 PATHTREE_TYPE_PATHS = 1 12 PATHTREE_TYPE_VALUES = 2 13 PATHTREE_TYPE_ENTRIES = 3 14 ) 15 16 type PathTree struct { 17 Top *ENTRY 18 count int 19 lock sync.Mutex 20 } 21 22 func NewPathTree() *PathTree { 23 p := new(PathTree) 24 25 p.Top = NewENTRY() 26 27 return p 28 } 29 30 func (this *PathTree) Insert(path string, value interface{}) interface{} { 31 32 if path == "" { 33 return nil 34 } 35 36 return this.InsertArray(strings.Split(path, "/"), value) 37 //return insert(StringUtil.split(path, '/'), value); 38 } 39 40 func (this *PathTree) InsertArray(paths []string, value interface{}) interface{} { 41 this.lock.Lock() 42 defer this.lock.Unlock() 43 44 if paths == nil || len(paths) == 0 || value == nil { 45 return nil 46 } 47 if len(paths) == 1 { 48 return nil 49 } 50 path := NewPATH(paths) 51 52 if this.Top.child == nil { 53 cur := this.Top 54 cur.child = NewENTRY() 55 cur.child.parent = cur 56 cur = cur.child 57 cur.node = path.Node() 58 this.count++ 59 60 //fmt.Println("PathTree.InsertArray expand count=" , this.count) 61 return this.expand(cur, path, value) 62 } else { 63 //fmt.Println("PathTree.InsertArray insert") 64 return this.insert(this.Top, this.Top.child, path, value) 65 } 66 } 67 68 func (this *PathTree) expand(cur *ENTRY, path *PATH, value interface{}) interface{} { 69 for path.HasChild() { 70 path.Level++ 71 cur.child = NewENTRY() 72 cur.child.parent = cur 73 cur = cur.child 74 cur.node = path.Node() 75 this.count++ 76 } 77 78 old := cur.value 79 cur.value = value 80 return old 81 } 82 83 func (this *PathTree) insert(p *ENTRY, cur *ENTRY, path *PATH, value interface{}) interface{} { 84 85 if path.Node() == cur.node { 86 if path.HasChild() == false { 87 old := cur.value 88 cur.value = value 89 return old 90 } 91 path.Level++ 92 if cur.child != nil { 93 return this.insert(cur, cur.child, path, value) 94 } else { 95 cur.child = NewENTRY() 96 cur.child.parent = cur 97 cur = cur.child 98 cur.node = path.Node() 99 return this.expand(cur, path, value) 100 } 101 102 } else if cur.right != nil { 103 return this.insert(p, cur.right, path, value) 104 } else { 105 106 if path.Node() == "*" { 107 // *노드는 오른쪽끝에 추가한다. 108 cur.right = NewENTRY() 109 cur.right.parent = p 110 cur = cur.right 111 cur.node = path.Node() 112 this.count++ 113 return this.expand(cur, path, value) 114 } else { 115 // 일반 노드는 부모 노드의 첫번째 자식으로 등록한다. 116 cur = NewENTRY() 117 cur.parent = p 118 cur.right = p.child 119 p.child = cur 120 cur.node = path.Node() 121 this.count++ 122 return this.expand(cur, path, value) 123 } 124 } 125 } 126 127 func (this *PathTree) Find(path string) interface{} { 128 var ret interface{} 129 defer func() { 130 if r := recover(); r != nil { 131 // logutil.Println("WA825", "PathTree.Find Recover", r) //, string(debug.Stack())) 132 ret = nil 133 } 134 }() 135 136 if path == "" { 137 return nil 138 } 139 ret = this.FindArray(strings.Split(path, "/")) 140 141 return ret 142 } 143 144 func (this *PathTree) FindArray(path []string) interface{} { 145 var ret interface{} 146 defer func() { 147 if r := recover(); r != nil { 148 // logutil.Println("WA826", "PathTree.Find Recover", r) //, string(debug.Stack())) 149 ret = nil 150 } 151 }() 152 153 if path == nil || len(path) == 0 { 154 return nil 155 } 156 ret = this.find(this.Top.child, NewPATH(path)) 157 return ret 158 } 159 160 func (this *PathTree) find(cur *ENTRY, m *PATH) interface{} { 161 //logutil.Println("find =", m.Node()) 162 // Node 비어있을 경우 예외처리 163 if cur == nil { 164 return nil 165 } 166 167 if cur.Include(m.Node()) { 168 if m.HasChild() == false { 169 return cur.value 170 } 171 m.Level++ 172 173 if cur.child != nil { 174 return this.find(cur.child, m) 175 } 176 } else if cur.right != nil { 177 return this.find(cur.right, m) 178 } 179 return nil 180 } 181 182 func (this *PathTree) Size() int { 183 return this.count 184 } 185 186 func (this *PathTree) Paths() PathTreeEnumeration { 187 return NewPathTreeEnumer(PATHTREE_TYPE_PATHS) 188 } 189 190 func (this *PathTree) Values() PathTreeEnumeration { 191 return NewPathTreeEnumer(PATHTREE_TYPE_VALUES) 192 } 193 194 func (this *PathTree) Entries() PathTreeEnumeration { 195 return NewPathTreeEnumer(PATHTREE_TYPE_ENTRIES) 196 } 197 198 type PathTreeEnumeration interface { 199 HasMoreElements() bool 200 NextElement(top *ENTRY) interface{} 201 } 202 203 type PathTreeEnumer struct { 204 entry *ENTRY 205 Type int 206 } 207 208 func NewPathTreeEnumer(Type int) *PathTreeEnumer { 209 p := new(PathTreeEnumer) 210 p.Type = Type 211 return p 212 } 213 214 func (this *PathTreeEnumer) HasMoreElements() bool { 215 return this.entry != nil 216 } 217 218 func (this *PathTreeEnumer) NextElement(top *ENTRY) interface{} { 219 if this.entry == nil { 220 //throw new NoSuchElementException("no more next"); 221 return nil 222 } 223 224 e := this.entry 225 if this.entry.child != nil { 226 this.entry = this.entry.child 227 } else { 228 for this.entry != nil && this.entry.right == nil { 229 this.entry = this.entry.parent 230 if this.entry == top { 231 this.entry = nil 232 switch this.Type { 233 case PATHTREE_TYPE_PATHS: 234 return e.Path(top) 235 case PATHTREE_TYPE_VALUES: 236 return e.Value 237 default: 238 return e 239 } 240 } 241 } 242 if this.entry != nil { 243 this.entry = this.entry.right 244 } 245 } 246 switch this.Type { 247 case PATHTREE_TYPE_PATHS: 248 return e.Path(top) 249 case PATHTREE_TYPE_VALUES: 250 return e.value 251 default: 252 return e 253 } 254 } 255 256 type PATH struct { 257 Nodes []string 258 Level int 259 } 260 261 func NewPATH(nodes []string) *PATH { 262 p := new(PATH) 263 p.Nodes = nodes 264 265 return p 266 } 267 268 func (this *PATH) HasChild() bool { 269 return (this.Level+1 < len(this.Nodes)) 270 } 271 272 func (this *PATH) Node() string { 273 return this.Nodes[this.Level] 274 } 275 276 type ENTRY struct { 277 node string 278 value interface{} 279 right *ENTRY 280 child *ENTRY 281 parent *ENTRY 282 } 283 284 func NewENTRY() *ENTRY { 285 p := new(ENTRY) 286 return p 287 } 288 289 func (this *ENTRY) Include(v string) bool { 290 return (this.node == "*" && v != "") || this.node == v 291 } 292 293 func (this *ENTRY) Value() interface{} { 294 return this.value 295 } 296 297 func (this *ENTRY) Node() string { 298 return this.node 299 } 300 301 func (this *ENTRY) Path(top *ENTRY) []string { 302 cur := this 303 304 // TODO 305 sk := list.New() 306 for cur != top { 307 sk.PushFront(cur.node) 308 //sk.add(cur.node); 309 cur = cur.parent 310 } 311 312 arr := make([]string, sk.Len()) 313 i := 0 314 for e := sk.Back(); e != nil; e = e.Next() { 315 arr[i] = e.Value.(string) 316 i++ 317 } 318 319 return arr 320 } 321 322 // public static void main(String[] args) { 323 // PathTree<String> t = new PathTree<String>(); 324 // t.insert("/cube/pcode/*/history/series", "/cube/pcode/{pcode}/history/series"); 325 // t.insert("/tx_country/pcode/*/cube/point", "/tx_country/pcode/{pcode}/cube/point"); 326 // t.insert("/rt_user/pcode/*/cube/series", "/rt_user/pcode/{pcode}/cube/series"); 327 // t.insert("/summary/pcode/*/cube", "/summary/pcode/{pcode}/cube"); 328 // t.insert("/hitmap/pcode/*/cube/series", "/hitmap/pcode/{pcode}/cube/series"); 329 // t.insert("/tx/pcode/*/top/cube", "/tx/pcode/{pcode}/top/cube"); 330 // t.insert("/event/pcode/*/top/cube", "/event/pcode/{pcode}/top/cube"); 331 // t.insert("/tps_res_time/pcode/*/cube/series", "/tps_res_time/pcode/{pcode}/cube/series"); 332 // t.insert("/cpu_heap/pcode/*/cube/series", "/cpu_heap/pcode/{pcode}/cube/series"); 333 // t.insert("/summary/pcode/*", "/summary/pcode/{pcode}"); 334 // t.insert("/counter/pcode/*/oid/*/{name}", "/counter/pcode/{pcode}/oid/{oid:.*}/{name}"); 335 // t.insert("/counter/pcode/*/name", "/counter/pcode/{pcode}/name"); 336 // t.insert("/stat/pcode/*/oid/*", "/stat/pcode/{pcode}/oid/{oid}"); 337 // t.insert("/report/pcode/*/daily/summary", "/report/pcode/{pcode}/daily/summary"); 338 // t.insert("/config/*/*/get", "/config/{pcode}/{oid:.*}/get"); 339 // t.insert("/config/*/*/set", "/config/{pcode}/{oid:.*}/set"); 340 // t.insert("/agent/pcode/*/oid/*/show_config", "/agent/pcode/{pcode}/oid/{oid:.*}/show_config"); 341 // t.insert("/agent/pcode/*/oid/*/add_config", "/agent/pcode/{pcode}/oid/{oid:.*}/add_config"); 342 // t.insert("/agent/pcode/*/oids", "/agent/pcode/{pcode}/oids"); 343 // t.insert("/agent/pcode/*/oid/*/remove", "/agent/pcode/{pcode}/oid/{oid}/remove"); 344 // t.insert("/agent/pcode/*/oid/*/env", "/agent/pcode/{pcode}/oid/{oid}/env"); 345 // t.insert("/agent/pcode/*/oid/*/threadlist", "/agent/pcode/{pcode}/oid/{oid:.*}/threadlist"); 346 // t.insert("/agent/pcode/*/oid/*/thread/{threadId}", "/agent/pcode/{pcode}/oid/{oid:.*}/thread/{threadId}"); 347 // t.insert("*", "${springfox.documentation.swagger.v2.path:/v2/api-docs}"); 348 // t.insert("/yard/pcode/*/oid", "/yard/pcode/{pcode}/oid"); 349 // t.insert("/yard/pcode/*/oid/*/oname", "/yard/pcode/{pcode}/oid/{oid}/oname"); 350 // t.insert("/yard/pcode/*/disk", "/yard/pcode/{pcode}/disk"); 351 // t.insert("/yard/pcode/*/disk/clear", "/yard/pcode/{pcode}/disk/clear"); 352 // 353 // 354 //// System.out.println(t.find("/pcode/123/disk/clear")); 355 //// System.out.println(t.find("/pcode/1234/disk")); 356 // System.out.println(t.find("/config/123/4/get")); 357 //// Enumeration<PathTree<String>.ENTRY> en = t.entries(); 358 //// while (en.hasMoreElements()) { 359 //// PathTree<String>.ENTRY e = en.nextElement(); 360 //// System.out.println(e.path() + "=>" + e.value()); 361 //// } 362 // } 363 364 func main() { 365 t := NewPathTree() 366 t.Insert("/api/internal/v1/panels/*", "/api/internal/v1/panels/{panelNo}") 367 t.Insert("/api/internal/v1/panels/push", "/api/internal/v1/panels/push") 368 fmt.Println(t.Find("/api/internal/v1/panels/123")) 369 fmt.Println(t.Find("/api/internal/v1/panels/push")) 370 }