diff --git a/utils/navigablemap.go b/utils/navigablemap.go new file mode 100644 index 000000000..76dd55d80 --- /dev/null +++ b/utils/navigablemap.go @@ -0,0 +1,272 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package utils + +import ( + "fmt" + "strings" +) + +// DataStorage is the new DataProvider +type DataStorage interface { + String() string // printable version of data + Get(fldPath []string) (interface{}, error) + GetString(fldPath []string) (string, error) + Set(fldPath []string, val interface{}) error + Remove(fldPath []string) error + GetKeys(nesteed bool) []string + // RemoteHost() net.Addr +} + +// MapStorage is the basic DataStorage +type MapStorage map[string]interface{} + +// String returns the map as json string +func (ms *MapStorage) String() string { return ToJSON(ms) } + +// Get returns the value from the path +func (ms *MapStorage) Get(fldPath []string) (val interface{}, err error) { + if len(fldPath) == 0 { + err = ErrNotFound + return + } + var has bool + if val, has = (*ms)[fldPath[0]]; !has { + err = ErrNotFound + return + } + if len(fldPath) == 1 { + return + } + ds, ok := val.(DataStorage) + if !ok { + err = fmt.Errorf("Wrong type") + return + } + return ds.Get(fldPath[1:]) +} + +// GetString returns thevalue from path as string +func (ms *MapStorage) GetString(fldPath []string) (str string, err error) { + var val interface{} + if val, err = ms.Get(fldPath); err != nil { + return + } + return IfaceAsString(val), nil +} + +// Set sets the value at the given path +func (ms *MapStorage) Set(fldPath []string, val interface{}) (err error) { + if len(fldPath) == 0 { + return fmt.Errorf("Wrong path") + } + if len(fldPath) == 1 { + (*ms)[fldPath[0]] = val + return + } + nMap := &MapStorage{} + (*ms)[fldPath[0]] = nMap + return nMap.Set(fldPath[1:], val) +} + +// GetKeys returns all the keys from map +func (ms *MapStorage) GetKeys(nesteed bool) (keys []string) { + for k, v := range *ms { + keys = append(keys, k) + if !nesteed { + continue + } + ds, ok := v.(DataStorage) + if !ok { + continue + } + for _, dsKey := range ds.GetKeys(nesteed) { + keys = append(keys, k+NestingSep+dsKey) + } + } + return +} + +// Remove removes the item at path +func (ms *MapStorage) Remove(fldPath []string) (err error) { + if len(fldPath) == 0 { + return fmt.Errorf("Wrong path") + } + var val interface{} + var has bool + if val, has = (*ms)[fldPath[0]]; !has { + return // ignore (already removed) + } + if len(fldPath) == 1 { + delete(*ms, fldPath[0]) + return + } + ds, ok := val.(DataStorage) + if !ok { + err = fmt.Errorf("Wrong type") + return + } + return ds.Remove(fldPath[1:]) +} + +// NavigableMap is a DataStorage +type NavigableMap map[string]DataStorage + +// String returns the map as json string +func (nm *NavigableMap) String() string { return ToJSON(nm) } + +// Get returns the value from the path +func (nm *NavigableMap) Get(fldPath []string) (val interface{}, err error) { + if len(fldPath) == 0 { + err = ErrNotFound + return + } + ds, has := (*nm)[fldPath[0]] + if !has { + err = ErrNotFound + return + } + if len(fldPath) == 1 { + val = ds + return + } + return ds.Get(fldPath[1:]) +} + +// GetString returns thevalue from path as string +func (nm *NavigableMap) GetString(fldPath []string) (str string, err error) { + var val interface{} + if val, err = nm.Get(fldPath); err != nil { + return + } + return IfaceAsString(val), nil +} + +// Set sets the value at the given path +func (nm *NavigableMap) Set(fldPath []string, val interface{}) (err error) { + if len(fldPath) == 0 { + return fmt.Errorf("Wrong path") + } + if len(fldPath) == 1 { + ds, ok := val.(DataStorage) + if !ok { + return fmt.Errorf("Wrong type") + } + (*nm)[fldPath[0]] = ds + return + } + if _, has := (*nm)[fldPath[0]]; !has { + (*nm)[fldPath[0]] = &MapStorage{} + } + return (*nm)[fldPath[0]].Set(fldPath[1:], val) +} + +// GetKeys returns all the keys from map +func (nm *NavigableMap) GetKeys(nesteed bool) (keys []string) { + for k, v := range *nm { + keys = append(keys, k) + if !nesteed { + continue + } + for _, dsKey := range v.GetKeys(nesteed) { + keys = append(keys, k+NestingSep+dsKey) + } + } + return +} + +// Remove removes the item at path +func (nm *NavigableMap) Remove(fldPath []string) (err error) { + if len(fldPath) == 0 { + return fmt.Errorf("Wrong path") + } + var val DataStorage + var has bool + if val, has = (*nm)[fldPath[0]]; !has { + return // ignore (already removed) + } + if len(fldPath) == 1 { + delete(*nm, fldPath[0]) + return + } + return val.Remove(fldPath[1:]) +} + +// NewOrderedNavigableMap initializates a structure of OrderedNavigableMap with a NavigableMap +func NewOrderedNavigableMap(nm *NavigableMap) *OrderedNavigableMap { + if nm == nil { + return &OrderedNavigableMap{ + nm: &NavigableMap{}, + order: [][]string{}, + } + } + keys := nm.GetKeys(true) + order := make([][]string, len(keys)) + for i, k := range keys { + order[i] = strings.Split(k, NestingSep) + } + return &OrderedNavigableMap{ + nm: nm, + order: order, + } +} + +// OrderedNavigableMap is the same as NavigableMap but keeps the order of fields +type OrderedNavigableMap struct { + nm *NavigableMap + order [][]string +} + +// String returns the map as json string +func (onm *OrderedNavigableMap) String() string { return ToJSON(onm.nm) } + +// Get returns the value from the path +func (onm *OrderedNavigableMap) Get(fldPath []string) (val interface{}, err error) { + return onm.nm.Get(fldPath) +} + +// GetString returns thevalue from path as string +func (onm *OrderedNavigableMap) GetString(fldPath []string) (str string, err error) { + return onm.nm.GetString(fldPath) +} + +// Set sets the value at the given path +func (onm *OrderedNavigableMap) Set(fldPath []string, val interface{}) (err error) { + if err = onm.nm.Set(fldPath, val); err == nil { + onm.order = append(onm.order, fldPath) + } + return +} + +// GetKeys returns all the keys from map +func (onm *OrderedNavigableMap) GetKeys(nesteed bool) (keys []string) { + keys = make([]string, len(onm.order)) + for i, k := range onm.order { + keys[i] = strings.Join(k, NestingSep) + } + return +} + +// Remove removes the item at path +func (onm *OrderedNavigableMap) Remove(fldPath []string) (err error) { + if len(fldPath) == 0 { + return fmt.Errorf("Wrong path") + } + return onm.nm.Remove(fldPath) +}