VOL-1283: Fixed callback execution consistency for all proxy levels

- Callbacks are executed at any proxy levels
- Uncovered some issues with the base children fields structure
- cleaned up the root/node structures
- Ensure that a get command returns a clone.

Change-Id: Ic2cd5420c29332bd9b5d6f303a7fd9d0d0ccaf06
diff --git a/db/model/node.go b/db/model/node.go
index 75f6915..4a92208 100644
--- a/db/model/node.go
+++ b/db/model/node.go
@@ -48,10 +48,14 @@
 	FoldTxBranch(txid string)
 
 	GetProxy(path string, exclusive bool) *Proxy
+
+	ExecuteCallbacks()
+	AddCallback(callback CallbackFunction, args ...interface{})
+	AddNotificationCallback(callback CallbackFunction, args ...interface{})
 }
 
 type node struct {
-	root      *root
+	Root      *root
 	Type      interface{}
 	Branches  map[string]*Branch
 	Tags      map[string]Revision
@@ -69,7 +73,7 @@
 func NewNode(root *root, initialData interface{}, autoPrune bool, txid string) *node {
 	n := &node{}
 
-	n.root = root
+	n.Root = root
 	n.Branches = make(map[string]*Branch)
 	n.Tags = make(map[string]Revision)
 	n.Proxy = nil
@@ -91,11 +95,15 @@
 }
 
 func (n *node) MakeNode(data interface{}, txid string) *node {
-	return NewNode(n.root, data, true, txid)
+	return NewNode(n.Root, data, true, txid)
 }
 
 func (n *node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
-	return n.root.MakeRevision(branch, data, children)
+	if n.Root.RevisionClass.(reflect.Type) == reflect.TypeOf(PersistedRevision{}) {
+		return NewPersistedRevision(branch, data, children)
+	}
+
+	return NewNonPersistedRevision(branch, data, children)
 }
 
 func (n *node) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
@@ -113,17 +121,30 @@
 	if changeAnnouncement != nil && branch.Txid == "" {
 		if n.Proxy != nil {
 			for _, change := range changeAnnouncement {
-				log.Debugf("invoking callback - changeType: %+v, previous:%+v, latest: %+v\n", change.Type,
-					change.PreviousData, change.LatestData)
-				n.root.AddCallback(n.Proxy.InvokeCallbacks, change.Type, change.PreviousData, change.LatestData, true)
+				log.Debugf("invoking callback - changeType: %+v, previous:%+v, latest: %+v",
+					change.Type,
+					change.PreviousData,
+					change.LatestData)
+				n.Root.AddCallback(
+					n.Proxy.InvokeCallbacks,
+					change.Type,
+					true,
+					change.PreviousData,
+					change.LatestData)
 			}
 		}
 
 		for _, change := range changeAnnouncement {
-			log.Debugf("sending notification - changeType: %+v, previous:%+v, latest: %+v\n", change.Type,
+			log.Debugf("sending notification - changeType: %+v, previous:%+v, latest: %+v",
+				change.Type,
 				change.PreviousData,
 				change.LatestData)
-			n.root.AddNotificationCallback(n.makeEventBus().Advertise, change.Type, change.PreviousData, change.LatestData, revision.GetHash())
+			n.Root.AddNotificationCallback(
+				n.makeEventBus().Advertise,
+				change.Type,
+				revision.GetHash(),
+				change.PreviousData,
+				change.LatestData)
 		}
 	}
 }
@@ -205,7 +226,7 @@
 
 		fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
 
-		log.Debugf("fieldValue: %+v, type: %+v, value: %+v", fieldValue.Interface(), fieldValue.Type(), value)
+		//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 {
@@ -313,7 +334,7 @@
 
 	if n.Proxy != nil {
 		log.Debug("invoking proxy GET Callbacks")
-		msg = n.Proxy.InvokeCallbacks(GET, msg, false)
+		msg = n.Proxy.InvokeCallbacks(GET, false, msg)
 
 	}
 	return msg
@@ -359,7 +380,7 @@
 
 	if field.IsContainer {
 		if path == "" {
-			log.Errorf("cannot update a list\n")
+			log.Errorf("cannot update a list")
 		} else if field.Key != "" {
 			partition := strings.SplitN(path, "/", 2)
 			key := partition[0]
@@ -376,7 +397,9 @@
 			}
 			idx, childRev := n.findRevByKey(children, field.Key, keyValue)
 			childNode := childRev.GetNode()
+			childNode.Proxy = n.Proxy
 			newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
+
 			if newChildRev.GetHash() == childRev.GetHash() {
 				if newChildRev != childRev {
 					log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
@@ -390,15 +413,15 @@
 			_newKeyType := fmt.Sprintf("%s", newKey)
 			_keyValueType := fmt.Sprintf("%s", keyValue)
 			if _newKeyType != _keyValueType {
-				log.Errorf("cannot change key field\n")
+				log.Errorf("cannot change key field")
 			}
 			children[idx] = newChildRev
 			rev = rev.UpdateChildren(name, children, branch)
 			branch.Latest.Drop(txid, false)
-			n.root.MakeLatest(branch, rev, nil)
+			n.MakeLatest(branch, rev, nil)
 			return rev
 		} else {
-			log.Errorf("cannot index into container with no keys\n")
+			log.Errorf("cannot index into container with no keys")
 		}
 	} else {
 		childRev := rev.GetChildren()[name][0]
@@ -406,7 +429,7 @@
 		newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
 		rev = rev.UpdateChildren(name, []Revision{newChildRev}, branch)
 		branch.Latest.Drop(txid, false)
-		n.root.MakeLatest(branch, rev, nil)
+		n.MakeLatest(branch, rev, nil)
 		return rev
 	}
 	return nil
@@ -428,7 +451,7 @@
 
 	if n.Proxy != nil {
 		log.Debug("invoking proxy PRE_UPDATE Callbacks")
-		n.Proxy.InvokeCallbacks(PRE_UPDATE, data, false)
+		n.Proxy.InvokeCallbacks(PRE_UPDATE, false, branch.Latest.GetData(), data)
 	}
 	if !reflect.DeepEqual(branch.Latest.GetData(), data) {
 		if strict {
@@ -438,7 +461,7 @@
 		rev := branch.Latest.UpdateData(data, branch)
 		changes := []ChangeTuple{{POST_UPDATE, branch.Latest.GetData(), rev.GetData()}}
 		branch.Latest.Drop(branch.Txid, true)
-		n.root.MakeLatest(branch, rev, changes)
+		n.MakeLatest(branch, rev, changes)
 		return rev
 	} else {
 		return branch.Latest
@@ -454,7 +477,7 @@
 	}
 	if path == "" {
 		// TODO raise error
-		log.Errorf("cannot add for non-container mode\n")
+		log.Errorf("cannot add for non-container mode")
 	}
 
 	var branch *Branch
@@ -484,7 +507,7 @@
 			if field.Key != "" {
 				if n.Proxy != nil {
 					log.Debug("invoking proxy PRE_ADD Callbacks")
-					n.Proxy.InvokeCallbacks(PRE_ADD, data, false)
+					n.Proxy.InvokeCallbacks(PRE_ADD, false, data)
 				}
 
 				for _, v := range rev.GetChildren()[name] {
@@ -492,20 +515,21 @@
 					children = append(children, revCopy)
 				}
 				_, key := GetAttributeValue(data, field.Key, 0)
-				if _, rev := n.findRevByKey(children, field.Key, key.String()); rev != nil {
+				if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
 					// TODO raise error
 					log.Errorf("duplicate key found: %s", key.String())
+				} else {
+					childRev := n.MakeNode(data, txid).Latest(txid)
+					children = append(children, childRev)
+					rev := rev.UpdateChildren(name, children, branch)
+					changes := []ChangeTuple{{POST_ADD, nil, rev.GetData()}}
+					branch.Latest.Drop(txid, false)
+					n.MakeLatest(branch, rev, changes)
+					return rev
 				}
 
-				childRev := n.MakeNode(data, txid).Latest(txid)
-				children = append(children, childRev)
-				rev := rev.UpdateChildren(name, children, branch)
-				changes := []ChangeTuple{{POST_ADD, branch.Latest.GetData(), rev.GetData()}}
-				branch.Latest.Drop(txid, false)
-				n.root.MakeLatest(branch, rev, changes)
-				return rev
 			} else {
-				log.Errorf("cannot add to non-keyed container\n")
+				log.Errorf("cannot add to non-keyed container")
 			}
 		} else if field.Key != "" {
 			partition := strings.SplitN(path, "/", 2)
@@ -523,13 +547,13 @@
 			children[idx] = newChildRev
 			rev := rev.UpdateChildren(name, children, branch)
 			branch.Latest.Drop(txid, false)
-			n.root.MakeLatest(branch, rev, nil)
+			n.MakeLatest(branch, rev, nil)
 			return rev
 		} else {
-			log.Errorf("cannot add to non-keyed container\n")
+			log.Errorf("cannot add to non-keyed container")
 		}
 	} else {
-		log.Errorf("cannot add to non-container field\n")
+		log.Errorf("cannot add to non-container field")
 	}
 	return nil
 }
@@ -543,7 +567,7 @@
 	}
 	if path == "" {
 		// TODO raise error
-		log.Errorf("cannot remove for non-container mode\n")
+		log.Errorf("cannot remove for non-container mode")
 	}
 	var branch *Branch
 	var ok bool
@@ -569,7 +593,7 @@
 
 	if field.IsContainer {
 		if path == "" {
-			log.Errorf("cannot remove without a key\n")
+			log.Errorf("cannot remove without a key")
 		} else if field.Key != "" {
 			partition := strings.SplitN(path, "/", 2)
 			key := partition[0]
@@ -590,7 +614,7 @@
 				children[idx] = newChildRev
 				rev := rev.UpdateChildren(name, children, branch)
 				branch.Latest.Drop(txid, false)
-				n.root.MakeLatest(branch, rev, nil)
+				n.MakeLatest(branch, rev, nil)
 				return rev
 			} else {
 				for _, v := range rev.GetChildren()[name] {
@@ -600,7 +624,7 @@
 				idx, childRev := n.findRevByKey(children, field.Key, keyValue)
 				if n.Proxy != nil {
 					data := childRev.GetData()
-					n.Proxy.InvokeCallbacks(PRE_REMOVE, data, false)
+					n.Proxy.InvokeCallbacks(PRE_REMOVE, false, data)
 					postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
 				} else {
 					postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
@@ -609,14 +633,14 @@
 				children = append(children[:idx], children[idx+1:]...)
 				rev := rev.UpdateChildren(name, children, branch)
 				branch.Latest.Drop(txid, false)
-				n.root.MakeLatest(branch, rev, postAnnouncement)
+				n.MakeLatest(branch, rev, postAnnouncement)
 				return rev
 			}
 		} else {
-			log.Errorf("cannot add to non-keyed container\n")
+			log.Errorf("cannot add to non-keyed container")
 		}
 	} else {
-		log.Errorf("cannot add to non-container field\n")
+		log.Errorf("cannot add to non-container field")
 	}
 
 	return nil
@@ -661,7 +685,7 @@
 	rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
 
 	if !dryRun {
-		n.root.MakeLatest(dstBranch, rev, changes)
+		n.MakeLatest(dstBranch, rev, changes)
 		delete(n.Branches, txid)
 	}
 
@@ -707,31 +731,34 @@
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 func (n *node) GetProxy(path string, exclusive bool) *Proxy {
-	r := NewRoot(n.Type, n.root.KvStore)
-	r.node = *n
-	r.KvStore = n.root.KvStore
+	//r := NewRoot(n.Type, n.KvStore)
+	//r.node = n
+	//r.KvStore = n.KvStore
 
-	return n.getProxy(path, r, path, exclusive)
+	return n.getProxy(path, path, exclusive)
 }
-func (n *node) getProxy(path string, root Root, fullPath string, exclusive bool) *Proxy {
+func (n *node) getProxy(path string, fullPath string, exclusive bool) *Proxy {
 	for strings.HasPrefix(path, "/") {
 		path = path[1:]
 	}
 	if path == "" {
-		return n.makeProxy(root, path, exclusive)
+		return n.makeProxy(path, exclusive)
 	}
 
 	rev := n.Branches[NONE].Latest
 	partition := strings.SplitN(path, "/", 2)
 	name := partition[0]
-	path = partition[1]
+	if len(partition) < 2 {
+		path = ""
+	} else {
+		path = partition[1]
+	}
 
 	field := ChildrenFields(n.Type)[name]
-	if field.IsContainer {
+	if field != nil && field.IsContainer {
 		if path == "" {
 			log.Error("cannot proxy a container field")
-		}
-		if field.Key != "" {
+		} else if field.Key != "" {
 			partition := strings.SplitN(path, "/", 2)
 			key := partition[0]
 			if len(partition) < 2 {
@@ -740,29 +767,40 @@
 				path = partition[1]
 			}
 			keyValue := field.KeyFromStr(key)
-			children := rev.GetChildren()[name]
+			var children []Revision
+			for _, v := range rev.GetChildren()[name] {
+				newV := reflect.ValueOf(v).Interface().(Revision)
+				children = append(children, newV)
+			}
 			_, childRev := n.findRevByKey(children, field.Key, keyValue)
 			childNode := childRev.GetNode()
 
-			r := NewRoot(childNode.Type, n.root.KvStore)
-			r.node = *childNode
-			r.KvStore = childNode.root.KvStore
-
-			return childNode.getProxy(path, r, fullPath, exclusive)
+			return childNode.getProxy(path, fullPath, exclusive)
+		} else {
+			log.Error("cannot index into container with no keys")
 		}
-		log.Error("cannot index into container with no keys")
 	} else {
 		childRev := rev.GetChildren()[name][0]
 		childNode := childRev.GetNode()
-		return childNode.getProxy(path, root, fullPath, exclusive)
+		return childNode.getProxy(path, fullPath, exclusive)
 	}
 
 	return nil
 }
 
-func (n *node) makeProxy(root Root, fullPath string, exclusive bool) *Proxy {
+func (n *node) makeProxy(fullPath string, exclusive bool) *Proxy {
+	r := &root{
+		node:                  n,
+		Callbacks:             n.Root.Callbacks,
+		NotificationCallbacks: n.Root.NotificationCallbacks,
+		DirtyNodes:            n.Root.DirtyNodes,
+		KvStore:               n.Root.KvStore,
+		Loading:               n.Root.Loading,
+		RevisionClass:         n.Root.RevisionClass,
+	}
+
 	if n.Proxy == nil {
-		n.Proxy = NewProxy(root, n, fullPath, exclusive)
+		n.Proxy = NewProxy(r, fullPath, exclusive)
 	} else {
 		if n.Proxy.Exclusive {
 			log.Error("node is already owned exclusively")
@@ -780,20 +818,14 @@
 
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Persistence Loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-func (n *node) LoadLatest(kvStore *Backend, hash string) {
+func (n *node) LoadLatest(hash string) {
 	branch := NewBranch(n, "", nil, n.AutoPrune)
 	pr := &PersistedRevision{}
-	rev := pr.Load(branch, kvStore, n.Type, hash)
+	rev := pr.Load(branch, n.Root.KvStore, n.Type, hash)
 	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)
+func (n *node) ExecuteCallbacks() {
+	n.Root.ExecuteCallbacks()
 }