package context import "sync" type ContextKey string func (c ContextKey) String() string { return string(c) } func NewContext(parent Context) Context { c := &defaultContext{ Context: parent, } c.attributes = make(map[string]interface{}) return c } type Context interface { Parent() Context SetAttribute(key string, value interface{}) GetAttribute(key string) (value interface{}) RemoveAttribute(key string) ContainsAttribute(key string) (exist bool) } type defaultContext struct { Context attributes map[string]interface{} mtx sync.RWMutex } func (dc *defaultContext) Parent() Context { return dc.Context } func (dc *defaultContext) SetAttribute(key string, value interface{}) { dc.checkInitialized() dc.mtx.Lock() defer dc.mtx.Unlock() dc.attributes[key] = value } func (dc *defaultContext) GetAttribute(key string) (value interface{}) { dc.checkInitialized() dc.mtx.RLock() defer dc.mtx.RUnlock() if _, ok := dc.attributes[key]; ok { return dc.attributes[key] } if nil == dc.Context { return nil } return dc.Context.GetAttribute(key) } func (dc *defaultContext) RemoveAttribute(key string) { dc.checkInitialized() dc.mtx.Lock() defer dc.mtx.Unlock() if _, ok := dc.attributes[key]; ok { delete(dc.attributes, key) return } if nil == dc.Context { return } dc.Context.RemoveAttribute(key) } func (dc *defaultContext) ContainsAttribute(key string) (exist bool) { dc.checkInitialized() dc.mtx.RLock() defer dc.mtx.RUnlock() if _, ok := dc.attributes[key]; ok { return true } if nil == dc.Context { return false } return dc.Context.ContainsAttribute(key) } func (dc *defaultContext) checkInitialized() { if nil == dc.attributes { panic("Attribute Manager: must be initialized") } }