VOL-1255: Fixed an issue with the proxy implementation

- Had to change the model slightly to mimic a polymorphic behaviour

Change-Id: I12017cdfedf5c0ed05243245aa2a811556222e0f
diff --git a/db/model/branch.go b/db/model/branch.go
index b59f727..ae0441a 100644
--- a/db/model/branch.go
+++ b/db/model/branch.go
@@ -19,14 +19,14 @@
 // TODO: missing proper logging
 
 type Branch struct {
-	Node      *Node
+	Node      *node
 	Txid      string
 	Origin    Revision
 	Revisions map[string]Revision
 	Latest    Revision
 }
 
-func NewBranch(node *Node, txid string, origin Revision, autoPrune bool) *Branch {
+func NewBranch(node *node, txid string, origin Revision, autoPrune bool) *Branch {
 	cb := &Branch{}
 	cb.Node = node
 	cb.Txid = txid
diff --git a/db/model/branch_test.go b/db/model/branch_test.go
index 456ec79..1f2eec2 100644
--- a/db/model/branch_test.go
+++ b/db/model/branch_test.go
@@ -27,7 +27,7 @@
 )
 
 func Test_ConfigBranch_New(t *testing.T) {
-	node := &Node{}
+	node := &node{}
 	hash := fmt.Sprintf("%x", md5.Sum([]byte("origin_hash")))
 	origin := &NonPersistedRevision{
 		Config:   &DataRevision{},
diff --git a/db/model/child_type.go b/db/model/child_type.go
index 13b0245..de2fad7 100644
--- a/db/model/child_type.go
+++ b/db/model/child_type.go
@@ -88,15 +88,24 @@
 								return s
 							}
 						case "int32":
-							fallthrough
+							keyFromStr = func(s string) interface{} {
+								i, _ := strconv.Atoi(s)
+								return int32(i)
+							}
 						case "int64":
-							fallthrough
+							keyFromStr = func(s string) interface{} {
+								i, _ := strconv.Atoi(s)
+								return int64(i)
+							}
 						case "uint32":
-							fallthrough
+							keyFromStr = func(s string) interface{} {
+								i, _ := strconv.Atoi(s)
+								return uint32(i)
+							}
 						case "uint64":
 							keyFromStr = func(s string) interface{} {
 								i, _ := strconv.Atoi(s)
-								return i
+								return uint64(i)
 							}
 						default:
 							fmt.Errorf("Key type not implemented - type: %s\n", keyType.(reflect.Type))
diff --git a/db/model/node.go b/db/model/node.go
index fd58cf8..2ff199f 100644
--- a/db/model/node.go
+++ b/db/model/node.go
@@ -30,8 +30,28 @@
 	NONE string = "none"
 )
 
-type Node struct {
-	root      *Root
+type Node interface {
+	MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple)
+
+	// CRUD functions
+	Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision
+	Get(path string, hash string, depth int, deep bool, txid string) interface{}
+	Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision
+	Remove(path string, txid string, makeBranch MakeBranchFunction) Revision
+
+	MakeBranch(txid string) *Branch
+	DeleteBranch(txid string)
+	MergeBranch(txid string, dryRun bool) (Revision, error)
+
+	MakeTxBranch() string
+	DeleteTxBranch(txid string)
+	FoldTxBranch(txid string)
+
+	GetProxy(path string, exclusive bool) *Proxy
+}
+
+type node struct {
+	root      *root
 	Type      interface{}
 	Branches  map[string]*Branch
 	Tags      map[string]Revision
@@ -45,8 +65,8 @@
 	Data interface{}
 }
 
-func NewNode(root *Root, initialData interface{}, autoPrune bool, txid string) *Node {
-	n := &Node{}
+func NewNode(root *root, initialData interface{}, autoPrune bool, txid string) *node {
+	n := &node{}
 
 	n.root = root
 	n.Branches = make(map[string]*Branch)
@@ -69,15 +89,18 @@
 	return n
 }
 
-func (n *Node) MakeNode(data interface{}, txid string) *Node {
+func (n *node) MakeNode(data interface{}, txid string) *node {
 	return NewNode(n.root, data, true, txid)
 }
 
-func (n *Node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
+func (n *node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
 	return n.root.MakeRevision(branch, data, children)
 }
 
-func (n *Node) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
+func (n *node) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
+	n.makeLatest(branch, revision, changeAnnouncement)
+}
+func (n *node) makeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
 	if _, ok := branch.Revisions[revision.GetHash()]; !ok {
 		branch.Revisions[revision.GetHash()] = revision
 	}
@@ -90,18 +113,18 @@
 		if n.Proxy != nil {
 			for _, change := range changeAnnouncement {
 				fmt.Printf("invoking callback - changeType: %+v, data:%+v\n", change.Type, change.Data)
-				n.root.addCallback(n.Proxy.InvokeCallbacks, change.Type, change.Data, true)
+				n.root.AddCallback(n.Proxy.InvokeCallbacks, change.Type, change.Data, true)
 			}
 		}
 
 		for _, change := range changeAnnouncement {
 			fmt.Printf("sending notification - changeType: %+v, data:%+v\n", change.Type, change.Data)
-			n.root.addNotificationCallback(n.makeEventBus().Advertise, change.Type, change.Data, revision.GetHash())
+			n.root.AddNotificationCallback(n.makeEventBus().Advertise, change.Type, change.Data, revision.GetHash())
 		}
 	}
 }
 
-func (n *Node) Latest(txid ...string) Revision {
+func (n *node) Latest(txid ...string) Revision {
 	var branch *Branch
 	var exists bool
 
@@ -115,11 +138,11 @@
 	return nil
 }
 
-func (n *Node) GetHash(hash string) Revision {
+func (n *node) GetHash(hash string) Revision {
 	return n.Branches[NONE].Revisions[hash]
 }
 
-func (n *Node) initialize(data interface{}, txid string) {
+func (n *node) initialize(data interface{}, txid string) {
 	var children map[string][]Revision
 	children = make(map[string][]Revision)
 	for fieldName, field := range ChildrenFields(n.Type) {
@@ -162,7 +185,7 @@
 	//data.ClearField(field_name)
 	branch := NewBranch(n, "", nil, n.AutoPrune)
 	rev := n.MakeRevision(branch, data, children)
-	n.MakeLatest(branch, rev, nil)
+	n.makeLatest(branch, rev, nil)
 
 	if txid == "" {
 		n.Branches[NONE] = branch
@@ -171,10 +194,30 @@
 	}
 }
 
+func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
+	for i, rev := range revs {
+		dataValue := reflect.ValueOf(rev.GetData())
+		dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
+
+		fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
+
+		log.Debugf("fieldValue: %+v, type: %+v, value: %+v", fieldValue.Interface(), fieldValue.Type(), value)
+		a := fmt.Sprintf("%s", fieldValue.Interface())
+		b := fmt.Sprintf("%s", value)
+		if a == b {
+			return i, rev
+		}
+	}
+
+	fmt.Errorf("key %s=%s not found", keyName, value)
+
+	return -1, nil
+}
+
 //
 // Get operation
 //
-func (n *Node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
+func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
 	if deep {
 		depth = -1
 	}
@@ -197,29 +240,12 @@
 		rev = branch.Latest
 	}
 
-	return n.get(rev, path, depth)
+	return n.getPath(rev, path, depth)
 }
 
-func (n *Node) findRevByKey(revs []Revision, keyName string, value string) (int, Revision) {
-	for i, rev := range revs {
-		dataValue := reflect.ValueOf(rev.GetData())
-		dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
-
-		fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
-
-		if fieldValue.Interface().(string) == value {
-			return i, rev
-		}
-	}
-
-	fmt.Errorf("key %s=%s not found", keyName, value)
-
-	return -1, nil
-}
-
-func (n *Node) get(rev Revision, path string, depth int) interface{} {
+func (n *node) getPath(rev Revision, path string, depth int) interface{} {
 	if path == "" {
-		return n.doGet(rev, depth)
+		return n.getData(rev, depth)
 	}
 
 	partition := strings.SplitN(path, "/", 2)
@@ -234,25 +260,25 @@
 	names := ChildrenFields(n.Type)
 	field := names[name]
 
-	if field != nil && field.IsContainer {
+	if field.IsContainer {
 		if field.Key != "" {
 			children := rev.GetChildren()[name]
 			if path != "" {
 				partition = strings.SplitN(path, "/", 2)
 				key := partition[0]
 				path = ""
-				key = field.KeyFromStr(key).(string)
-				if _, childRev := n.findRevByKey(children, field.Key, key); childRev == nil {
+				keyValue := field.KeyFromStr(key)
+				if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
 					return nil
 				} else {
 					childNode := childRev.GetNode()
-					return childNode.get(childRev, path, depth)
+					return childNode.getPath(childRev, path, depth)
 				}
 			} else {
 				var response []interface{}
 				for _, childRev := range children {
 					childNode := childRev.GetNode()
-					value := childNode.doGet(childRev, depth)
+					value := childNode.getData(childRev, depth)
 					response = append(response, value)
 				}
 				return response
@@ -265,21 +291,20 @@
 			}
 			for _, childRev := range rev.GetChildren()[name] {
 				childNode := childRev.GetNode()
-				value := childNode.doGet(childRev, depth)
+				value := childNode.getData(childRev, depth)
 				response = append(response, value)
 			}
 			return response
 		}
 	} else {
-		c1 := rev.GetChildren()[name]
-		childRev := c1[0]
+		childRev := rev.GetChildren()[name][0]
 		childNode := childRev.GetNode()
-		return childNode.get(childRev, path, depth)
+		return childNode.getPath(childRev, path, depth)
 	}
 	return nil
 }
 
-func (n *Node) doGet(rev Revision, depth int) interface{} {
+func (n *node) getData(rev Revision, depth int) interface{} {
 	msg := rev.Get(depth)
 
 	if n.Proxy != nil {
@@ -293,7 +318,7 @@
 //
 // Update operation
 //
-func (n *Node) Update(path string, data interface{}, strict bool, txid string, makeBranch t_makeBranch) Revision {
+func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
 	// FIXME: is this required ... a bit overkill to take out a "/"
 	for strings.HasPrefix(path, "/") {
 		path = path[1:]
@@ -339,13 +364,13 @@
 			} else {
 				path = partition[1]
 			}
-			key = field.KeyFromStr(key).(string)
+			keyValue := field.KeyFromStr(key)
 			// TODO. Est-ce que le copy ne fonctionne pas? dois-je plutôt faire un clone de chaque item?
 			for _, v := range rev.GetChildren()[name] {
 				revCopy := reflect.ValueOf(v).Interface().(Revision)
 				children = append(children, revCopy)
 			}
-			idx, childRev := n.findRevByKey(children, field.Key, key)
+			idx, childRev := n.findRevByKey(children, field.Key, keyValue)
 			childNode := childRev.GetNode()
 			newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
 			if newChildRev.GetHash() == childRev.GetHash() {
@@ -355,7 +380,12 @@
 				}
 				return branch.Latest
 			}
-			if _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0); newKey.Interface().(string) != key {
+
+			_, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
+			log.Debugf("newKey is %s", newKey.Interface())
+			_newKeyType := fmt.Sprintf("%s", newKey)
+			_keyValueType := fmt.Sprintf("%s", keyValue)
+			if _newKeyType != _keyValueType {
 				fmt.Errorf("cannot change key field\n")
 			}
 			children[idx] = newChildRev
@@ -378,7 +408,7 @@
 	return nil
 }
 
-func (n *Node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
+func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
 	log.Debugf("Comparing types - expected: %+v, actual: %+v", reflect.ValueOf(n.Type).Type(), reflect.TypeOf(data))
 
 	if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
@@ -413,7 +443,7 @@
 //
 // Add operation
 //
-func (n *Node) Add(path string, data interface{}, txid string, makeBranch t_makeBranch) Revision {
+func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
 	for strings.HasPrefix(path, "/") {
 		path = path[1:]
 	}
@@ -479,9 +509,9 @@
 			} else {
 				path = partition[1]
 			}
-			key = field.KeyFromStr(key).(string)
+			keyValue := field.KeyFromStr(key)
 			copy(children, rev.GetChildren()[name])
-			idx, childRev := n.findRevByKey(children, field.Key, key)
+			idx, childRev := n.findRevByKey(children, field.Key, keyValue)
 			childNode := childRev.GetNode()
 			newChildRev := childNode.Add(path, data, txid, makeBranch)
 			children[idx] = newChildRev
@@ -501,7 +531,7 @@
 //
 // Remove operation
 //
-func (n *Node) Remove(path string, txid string, makeBranch t_makeBranch) Revision {
+func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
 	for strings.HasPrefix(path, "/") {
 		path = path[1:]
 	}
@@ -542,13 +572,13 @@
 			} else {
 				path = partition[1]
 			}
-			key = field.KeyFromStr(key).(string)
+			keyValue := field.KeyFromStr(key)
 			if path != "" {
 				for _, v := range rev.GetChildren()[name] {
 					newV := reflect.ValueOf(v).Interface().(Revision)
 					children = append(children, newV)
 				}
-				idx, childRev := n.findRevByKey(children, field.Key, key)
+				idx, childRev := n.findRevByKey(children, field.Key, keyValue)
 				childNode := childRev.GetNode()
 				newChildRev := childNode.Remove(path, txid, makeBranch)
 				children[idx] = newChildRev
@@ -561,7 +591,7 @@
 					newV := reflect.ValueOf(v).Interface().(Revision)
 					children = append(children, newV)
 				}
-				idx, childRev := n.findRevByKey(children, field.Key, key)
+				idx, childRev := n.findRevByKey(children, field.Key, keyValue)
 				if n.Proxy != nil {
 					data := childRev.GetData()
 					n.Proxy.InvokeCallbacks(PRE_REMOVE, data, false)
@@ -588,25 +618,25 @@
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-type t_makeBranch func(*Node) *Branch
+type MakeBranchFunction func(*node) *Branch
 
-func (n *Node) makeTxBranch(txid string) *Branch {
+func (n *node) MakeBranch(txid string) *Branch {
 	branchPoint := n.Branches[NONE].Latest
 	branch := NewBranch(n, txid, branchPoint, true)
 	n.Branches[txid] = branch
 	return branch
 }
 
-func (n *Node) deleteTxBranch(txid string) {
+func (n *node) DeleteBranch(txid string) {
 	delete(n.Branches, txid)
 }
 
-func (n *Node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
+func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
 	f := func(rev Revision) Revision {
 		childBranch := rev.GetBranch()
 
 		if childBranch.Txid == txid {
-			rev, _ = childBranch.Node.mergeTxBranch(txid, dryRun)
+			rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
 		}
 
 		return rev
@@ -614,7 +644,7 @@
 	return f
 }
 
-func (n *Node) mergeTxBranch(txid string, dryRun bool) (Revision, error) {
+func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
 	srcBranch := n.Branches[txid]
 	dstBranch := n.Branches[NONE]
 
@@ -635,7 +665,7 @@
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-//func (n *Node) diff(hash1, hash2, txid string) {
+//func (n *node) diff(hash1, hash2, txid string) {
 //	branch := n.Branches[txid]
 //	rev1 := branch.get(hash1)
 //	rev2 := branch.get(hash2)
@@ -655,7 +685,7 @@
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-func (n *Node) hasChildren(data interface{}) bool {
+func (n *node) hasChildren(data interface{}) bool {
 	for fieldName, field := range ChildrenFields(n.Type) {
 		_, fieldValue := GetAttributeValue(data, fieldName, 0)
 
@@ -668,17 +698,21 @@
 	return false
 }
 
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-func (n *Node) GetProxy(path string, exclusive bool) *Proxy {
-	return n.getProxy(path, n.root, path, exclusive)
+func (n *node) GetProxy(path string, exclusive bool) *Proxy {
+	r := NewRoot(n.Type, n.root.KvStore)
+	r.node = *n
+	r.KvStore = n.root.KvStore
+
+	return n.getProxy(path, r, path, exclusive)
 }
-func (n *Node) getProxy(path string, root *Root, fullPath string, exclusive bool) *Proxy {
+func (n *node) getProxy(path string, root Root, fullPath string, exclusive bool) *Proxy {
 	for strings.HasPrefix(path, "/") {
 		path = path[1:]
 	}
 	if path == "" {
-		return n.makeProxy(n.root, path, exclusive)
+		return n.makeProxy(root, path, exclusive)
 	}
 
 	rev := n.Branches[NONE].Latest
@@ -694,12 +728,21 @@
 		if field.Key != "" {
 			partition := strings.SplitN(path, "/", 2)
 			key := partition[0]
-			path = partition[1]
-			key = field.KeyFromStr(key).(string)
+			if len(partition) < 2 {
+				path = ""
+			} else {
+				path = partition[1]
+			}
+			keyValue := field.KeyFromStr(key)
 			children := rev.GetChildren()[name]
-			_, childRev := n.findRevByKey(children, field.Key, key)
+			_, childRev := n.findRevByKey(children, field.Key, keyValue)
 			childNode := childRev.GetNode()
-			return childNode.getProxy(path, root, fullPath, exclusive)
+
+			r := NewRoot(childNode.Type, n.root.KvStore)
+			r.node = *childNode
+			r.KvStore = childNode.root.KvStore
+
+			return childNode.getProxy(path, r, fullPath, exclusive)
 		}
 		log.Error("cannot index into container with no keys")
 	} else {
@@ -711,7 +754,7 @@
 	return nil
 }
 
-func (n *Node) makeProxy(root *Root, fullPath string, exclusive bool) *Proxy {
+func (n *node) makeProxy(root Root, fullPath string, exclusive bool) *Proxy {
 	if n.Proxy == nil {
 		n.Proxy = NewProxy(root, n, fullPath, exclusive)
 	} else {
@@ -722,7 +765,7 @@
 	return n.Proxy
 }
 
-func (n *Node) makeEventBus() *EventBus {
+func (n *node) makeEventBus() *EventBus {
 	if n.EventBus == nil {
 		n.EventBus = NewEventBus()
 	}
@@ -731,10 +774,20 @@
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Persistence Loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-func (n *Node) LoadLatest(kvStore *Backend, hash string) {
+func (n *node) LoadLatest(kvStore *Backend, hash string) {
 	branch := NewBranch(n, "", nil, n.AutoPrune)
 	pr := &PersistedRevision{}
 	rev := pr.Load(branch, kvStore, n.Type, hash)
-	n.MakeLatest(branch, rev, nil)
+	n.makeLatest(branch, rev, nil)
 	n.Branches[NONE] = branch
 }
+
+func (n *node) MakeTxBranch() string {
+	return n.root.MakeTxBranch()
+}
+func (n *node) FoldTxBranch(txid string) {
+	n.root.FoldTxBranch(txid)
+}
+func (n *node) DeleteTxBranch(txid string) {
+	n.root.DeleteTxBranch(txid)
+}
diff --git a/db/model/node_test.go b/db/model/node_test.go
index 29f4c7c..3b12c14 100644
--- a/db/model/node_test.go
+++ b/db/model/node_test.go
@@ -66,7 +66,7 @@
 		PmConfigs:       &voltha.PmConfigs{},
 		ImageDownloads:  []*voltha.ImageDownload{},
 	}
-	root := &Root{}
+	root := &root{}
 	txid := fmt.Sprintf("%x", md5.Sum([]byte("node_transaction_id")))
 
 	node := NewNode(root, data, true, txid)
diff --git a/db/model/non_persisted_revision.go b/db/model/non_persisted_revision.go
index 8b81a48..99166e5 100644
--- a/db/model/non_persisted_revision.go
+++ b/db/model/non_persisted_revision.go
@@ -89,7 +89,7 @@
 	return npr.Config.Data
 }
 
-func (npr *NonPersistedRevision) GetNode() *Node {
+func (npr *NonPersistedRevision) GetNode() *node {
 	return npr.Branch.Node
 }
 
diff --git a/db/model/proxy.go b/db/model/proxy.go
index 3e33849..1939596 100644
--- a/db/model/proxy.go
+++ b/db/model/proxy.go
@@ -48,14 +48,14 @@
 }
 
 type Proxy struct {
-	Root      *Root
-	Node      *Node
+	Root      Root
+	Node      Node
 	Path      string
 	Exclusive bool
 	Callbacks map[CallbackType]map[string]CallbackTuple
 }
 
-func NewProxy(root *Root, node *Node, path string, exclusive bool) *Proxy {
+func NewProxy(root Root, node Node, path string, exclusive bool) *Proxy {
 	callbacks := make(map[CallbackType]map[string]CallbackTuple)
 	p := &Proxy{
 		Root:      root,
diff --git a/db/model/proxy_test.go b/db/model/proxy_test.go
index bf80bb7..a96aa28 100644
--- a/db/model/proxy_test.go
+++ b/db/model/proxy_test.go
@@ -29,7 +29,7 @@
 )
 
 type proxyTest struct {
-	Root      *Root
+	Root      *root
 	Backend   *Backend
 	Proxy     *Proxy
 	DbPrefix  string
@@ -66,7 +66,7 @@
 
 	GetProfiling().Report()
 
-	pt.Proxy = pt.Root.Node.GetProxy("/", false)
+	pt.Proxy = pt.Root.GetProxy("/", false)
 }
 
 func Test_Proxy_1_GetDevices(t *testing.T) {
@@ -121,6 +121,61 @@
 		t.Logf("Found device: count: %s", djson)
 	}
 }
+func Test_Proxy_3_1_RegisterProxy(t *testing.T) {
+	// Get a device proxy and update a specific port
+	devProxy := pt.Root.GetProxy("/devices/"+devId, false)
+	port123 := devProxy.Get("/ports/123", 0, false, "")
+	t.Logf("got ports: %+v", port123)
+
+	devProxy.RegisterCallback(POST_UPDATE, deviceCallback, nil)
+
+	port123.(*voltha.Port).OperStatus = common.OperStatus_DISCOVERED
+
+	devProxy.Update("/ports/123", port123, false, "")
+	updated := devProxy.Get("/ports", 0, false, "")
+	t.Logf("got updated ports: %+v", updated)
+
+	//
+	// Get a device proxy and update all its ports
+	//
+
+	//devProxy := pt.Root.GetProxy("/devices/"+devId, false)
+	//ports := devProxy.Get("/ports", 0, false, "")
+	//t.Logf("got ports: %+v", ports)
+	//devProxy.RegisterCallback(POST_UPDATE, deviceCallback, nil)
+	//
+	//ports.([]interface{})[0].(*voltha.Port).OperStatus = common.OperStatus_DISCOVERED
+	//
+	//devProxy.Update("/ports", ports, false, "")
+	//updated := devProxy.Get("/ports", 0, false, "")
+	//t.Logf("got updated ports: %+v", updated)
+
+
+	//
+	// Get a device proxy, retrieve all the ports and update a specific one
+	//
+
+	//devProxy := pt.Root.GetProxy("/devices/"+devId, false)
+	//ports := devProxy.Get("/ports", 0, false, "")
+	//t.Logf("got ports: %+v", ports)
+	//devProxy.RegisterCallback(POST_UPDATE, deviceCallback, nil)
+	//
+	//ports.([]interface{})[0].(*voltha.Port).OperStatus = common.OperStatus_DISCOVERED
+	//
+	//devProxy.Update("/ports/123", ports.([]interface{})[0], false, "")
+	//updated := devProxy.Get("/ports", 0, false, "")
+	//t.Logf("got updated ports: %+v", updated)
+}
+
+func Test_Proxy_3_2_GetDevice_PostRegister(t *testing.T) {
+	if d := pt.Proxy.Get("/devices/"+devId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+		t.Error("Failed to find updated registered device")
+	} else {
+		djson, _ := json.Marshal(d)
+
+		t.Logf("Found device: count: %s", djson)
+	}
+}
 
 func Test_Proxy_4_UpdateDevice(t *testing.T) {
 	if retrieved := pt.Proxy.Get("/devices/"+targetDeviceId, 1, false, ""); retrieved == nil {
@@ -179,6 +234,10 @@
 	fmt.Printf("Running first callback - name: %s, id: %s\n", name, id)
 	return nil
 }
+func deviceCallback(args ...interface{}) interface{} {
+	fmt.Printf("Running device callback\n")
+	return nil
+}
 func secondCallback(args ...interface{}) interface{} {
 	name := args[0].(map[string]string)
 	id := args[1]
diff --git a/db/model/revision.go b/db/model/revision.go
index a7b0c39..3912f67 100644
--- a/db/model/revision.go
+++ b/db/model/revision.go
@@ -29,7 +29,7 @@
 	GetBranch() *Branch
 	Get(int) interface{}
 	GetData() interface{}
-	GetNode() *Node
+	GetNode() *node
 	UpdateData(data interface{}, branch *Branch) Revision
 	UpdateChildren(name string, children []Revision, branch *Branch) Revision
 	UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision
diff --git a/db/model/root.go b/db/model/root.go
index 3e3cc43..a6c62c6 100644
--- a/db/model/root.go
+++ b/db/model/root.go
@@ -25,9 +25,14 @@
 	"time"
 )
 
-type Root struct {
-	*Node
-	DirtyNodes            map[string][]*Node
+type Root interface {
+	Node
+}
+
+type root struct {
+	node
+
+	DirtyNodes            map[string][]*node
 	KvStore               *Backend
 	Loading               bool
 	RevisionClass         interface{}
@@ -35,11 +40,12 @@
 	NotificationCallbacks []CallbackTuple
 }
 
-func NewRoot(initialData interface{}, kvStore *Backend) *Root {
-	root := &Root{}
+func NewRoot(initialData interface{}, kvStore *Backend) *root {
+	root := &root{}
 	root.KvStore = kvStore
-	root.DirtyNodes = make(map[string][]*Node)
+	root.DirtyNodes = make(map[string][]*node)
 	root.Loading = false
+
 	if kvStore != nil {
 		root.RevisionClass = reflect.TypeOf(PersistedRevision{})
 	} else {
@@ -48,12 +54,12 @@
 	root.Callbacks = []CallbackTuple{}
 	root.NotificationCallbacks = []CallbackTuple{}
 
-	root.Node = NewNode(root, initialData, false, "")
+	root.node = *NewNode(root, initialData, false, "")
 
 	return root
 }
 
-func (r *Root) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
+func (r *root) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
 	if r.RevisionClass.(reflect.Type) == reflect.TypeOf(PersistedRevision{}) {
 		return NewPersistedRevision(branch, data, children)
 	}
@@ -61,31 +67,31 @@
 	return NewNonPersistedRevision(branch, data, children)
 }
 
-func (r *Root) MakeTxBranch() string {
+func (r *root) MakeTxBranch() string {
 	txid_bin, _ := uuid.New().MarshalBinary()
 	txid := hex.EncodeToString(txid_bin)[:12]
-	r.DirtyNodes[txid] = []*Node{r.Node}
-	r.Node.makeTxBranch(txid)
+	r.DirtyNodes[txid] = []*node{&r.node}
+	r.node.MakeBranch(txid)
 	return txid
 }
 
-func (r *Root) DeleteTxBranch(txid string) {
+func (r *root) DeleteTxBranch(txid string) {
 	for _, dirtyNode := range r.DirtyNodes[txid] {
-		dirtyNode.deleteTxBranch(txid)
+		dirtyNode.DeleteBranch(txid)
 	}
 	delete(r.DirtyNodes, txid)
 }
 
-func (r *Root) FoldTxBranch(txid string) {
-	if _, err := r.mergeTxBranch(txid, true); err != nil {
+func (r *root) FoldTxBranch(txid string) {
+	if _, err := r.MergeBranch(txid, true); err != nil {
 		r.DeleteTxBranch(txid)
 	} else {
-		r.mergeTxBranch(txid, false)
-		r.executeCallbacks()
+		r.MergeBranch(txid, false)
+		r.ExecuteCallbacks()
 	}
 }
 
-func (r *Root) executeCallbacks() {
+func (r *root) ExecuteCallbacks() {
 	for len(r.Callbacks) > 0 {
 		callback := r.Callbacks[0]
 		r.Callbacks = r.Callbacks[1:]
@@ -98,105 +104,110 @@
 	}
 }
 
-func (r *Root) noCallbacks() bool {
+func (r *root) HasCallbacks() bool {
 	return len(r.Callbacks) == 0
 }
 
-func (r *Root) addCallback(callback CallbackFunction, args ...interface{}) {
+func (r *root) AddCallback(callback CallbackFunction, args ...interface{}) {
 	r.Callbacks = append(r.Callbacks, CallbackTuple{callback, args})
 }
-func (r *Root) addNotificationCallback(callback CallbackFunction, args ...interface{}) {
+func (r *root) AddNotificationCallback(callback CallbackFunction, args ...interface{}) {
 	r.NotificationCallbacks = append(r.NotificationCallbacks, CallbackTuple{callback, args})
 }
 
-func (r *Root) Update(path string, data interface{}, strict bool, txid string, makeBranch t_makeBranch) Revision {
+
+func (r *root) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
 	var result Revision
 
 	if makeBranch == nil {
 		// TODO: raise error
 	}
 
-	if r.noCallbacks() {
+	if r.HasCallbacks() {
 		// TODO: raise error
 	}
 
 	if txid != "" {
-		trackDirty := func(node *Node) *Branch {
+		trackDirty := func(node *node) *Branch {
 			r.DirtyNodes[txid] = append(r.DirtyNodes[txid], node)
-			return node.makeTxBranch(txid)
+			return node.MakeBranch(txid)
 		}
-		result = r.Node.Update(path, data, strict, txid, trackDirty)
+		result = r.node.Update(path, data, strict, txid, trackDirty)
 	} else {
-		result = r.Node.Update(path, data, strict, "", nil)
+		result = r.node.Update(path, data, strict, "", nil)
 	}
 
-	r.executeCallbacks()
+	r.ExecuteCallbacks()
 
 	return result
 }
 
-func (r *Root) Add(path string, data interface{}, txid string, makeBranch t_makeBranch) Revision {
+func (r *root) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
 	var result Revision
 
 	if makeBranch == nil {
 		// TODO: raise error
 	}
 
-	if r.noCallbacks() {
+	if r.HasCallbacks() {
 		// TODO: raise error
 	}
 
 	if txid != "" {
-		trackDirty := func(node *Node) *Branch {
+		trackDirty := func(node *node) *Branch {
 			r.DirtyNodes[txid] = append(r.DirtyNodes[txid], node)
-			return node.makeTxBranch(txid)
+			return node.MakeBranch(txid)
 		}
-		result = r.Node.Add(path, data, txid, trackDirty)
+		result = r.node.Add(path, data, txid, trackDirty)
 	} else {
-		result = r.Node.Add(path, data, "", nil)
+		result = r.node.Add(path, data, "", nil)
 	}
 
-	r.executeCallbacks()
+	r.ExecuteCallbacks()
 
 	return result
 }
 
-func (r *Root) Remove(path string, txid string, makeBranch t_makeBranch) Revision {
+func (r *root) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
 	var result Revision
 
 	if makeBranch == nil {
 		// TODO: raise error
 	}
 
-	if r.noCallbacks() {
+	if r.HasCallbacks() {
 		// TODO: raise error
 	}
 
 	if txid != "" {
-		trackDirty := func(node *Node) *Branch {
+		trackDirty := func(node *node) *Branch {
 			r.DirtyNodes[txid] = append(r.DirtyNodes[txid], node)
-			return node.makeTxBranch(txid)
+			return node.MakeBranch(txid)
 		}
-		result = r.Node.Remove(path, txid, trackDirty)
+		result = r.node.Remove(path, txid, trackDirty)
 	} else {
-		result = r.Node.Remove(path, "", nil)
+		result = r.node.Remove(path, "", nil)
 	}
 
-	r.executeCallbacks()
+	r.ExecuteCallbacks()
 
 	return result
 }
 
-func (r *Root) Load(rootClass interface{}) *Root {
+func (r *root) Load(rootClass interface{}) *root {
 	//fakeKvStore := &Backend{}
 	//root := NewRoot(rootClass, nil)
 	//root.KvStore = r.KvStore
-	r.loadFromPersistence(rootClass)
+	r.LoadFromPersistence(rootClass)
 	return r
 }
 
-func (r *Root) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
-	r.Node.MakeLatest(branch, revision, changeAnnouncement)
+func (r *root) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
+	r.makeLatest(branch, revision, changeAnnouncement)
+}
+
+func (r *root) makeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
+	r.node.makeLatest(branch, revision, changeAnnouncement)
 
 	if r.KvStore != nil && branch.Txid == "" {
 		tags := make(map[string]string)
@@ -218,8 +229,8 @@
 	}
 }
 
-func (r *Root) LoadLatest(hash string) {
-	r.Node.LoadLatest(r.KvStore, hash)
+func (r *root) LoadLatest(hash string) {
+	r.node.LoadLatest(r.KvStore, hash)
 }
 
 type rootData struct {
@@ -227,7 +238,7 @@
 	Tags   map[string]string `json:tags`
 }
 
-func (r *Root) loadFromPersistence(rootClass interface{}) {
+func (r *root) LoadFromPersistence(rootClass interface{}) {
 	var data rootData
 
 	r.Loading = true
@@ -240,10 +251,10 @@
 	stop := time.Now()
 	GetProfiling().AddToInMemoryModelTime(stop.Sub(start).Seconds())
 	for tag, hash := range data.Tags {
-		r.Node.LoadLatest(r.KvStore, hash)
-		r.Node.Tags[tag] = r.Node.Latest()
+		r.node.LoadLatest(r.KvStore, hash)
+		r.node.Tags[tag] = r.node.Latest()
 	}
 
-	r.Node.LoadLatest(r.KvStore, data.Latest)
+	r.node.LoadLatest(r.KvStore, data.Latest)
 	r.Loading = false
 }
diff --git a/db/model/root_test.go b/db/model/root_test.go
index 9c57730..68d7f2a 100644
--- a/db/model/root_test.go
+++ b/db/model/root_test.go
@@ -46,7 +46,7 @@
 	afterLoad := time.Now()
 	fmt.Printf(">>>>>>>>>>>>> Time to Load : %f\n", afterLoad.Sub(start).Seconds())
 
-	d := r.Node.Get(deviceProxy, "", 0, false, "")
+	d := r.node.Get(deviceProxy, "", 0, false, "")
 	afterGet := time.Now()
 	fmt.Printf(">>>>>>>>>>>>> Time to Load and get: %f\n", afterGet.Sub(start).Seconds())
 
diff --git a/db/model/transaction_test.go b/db/model/transaction_test.go
index 3b1b5bf..45e6c2d 100644
--- a/db/model/transaction_test.go
+++ b/db/model/transaction_test.go
@@ -27,7 +27,7 @@
 )
 
 type transactionTest struct {
-	Root      *Root
+	Root      *root
 	Backend   *Backend
 	Proxy     *Proxy
 	DbPrefix  string
@@ -69,7 +69,7 @@
 
 	GetProfiling().Report()
 
-	tx.Proxy = tx.Root.Node.GetProxy("/", false)
+	tx.Proxy = tx.Root.GetProxy("/", false)
 }
 
 func Test_Transaction_1_GetDevices(t *testing.T) {