package context import "sync" type AttributeManager interface { Attributes() Attributes } type Attributes interface { initialize() Set(key string, value interface{}) Get(key string) (value interface{}) Remove(key string) Contains(key string) (exist bool) Destroy() } func NewAttributes(parent Attributes) Attributes { am := &attributes{ Parent: parent, } am.initialize() return am } type attributes struct { Parent Attributes values map[string]interface{} mtx sync.RWMutex } func (am *attributes) initialize() { if nil != am.Parent { am.Parent.initialize() } if nil == am.values { am.Destroy() } am.values = make(map[string]interface{}) } func (am *attributes) Set(key string, value interface{}) { am.checkInitialized() am.mtx.Lock() defer am.mtx.Unlock() am.values[key] = value } func (am *attributes) Get(key string) (value interface{}) { am.checkInitialized() am.mtx.RLock() defer am.mtx.RUnlock() if _, ok := am.values[key]; ok { return am.values[key] } if nil == am.Parent { return nil } return am.Parent.Get(key) } func (am *attributes) Remove(key string) { am.checkInitialized() am.mtx.Lock() defer am.mtx.Unlock() if _, ok := am.values[key]; ok { delete(am.values, key) return } if nil == am.Parent { return } am.Parent.Remove(key) } func (am *attributes) Contains(key string) (exist bool) { am.checkInitialized() am.mtx.RLock() defer am.mtx.RUnlock() if _, ok := am.values[key]; ok { return true } if nil == am.Parent { return false } return am.Parent.Contains(key) } func (am *attributes) Destroy() { if nil != am.values { am.values = nil } if nil != am.Parent { am.Parent.Destroy() } } func (am *attributes) checkInitialized() { if nil == am.values { panic("Attribute Manager: must be initialized") } }