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  }