blob: 4a97941c90c03cc690cfc53267496a115a03285d [file] [log] [blame]
Stephane Barbarieec0919b2018-09-05 14:14:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package model
17
18import (
19 "bytes"
20 "crypto/md5"
21 "fmt"
22 "reflect"
23 "sort"
24 "github.com/opencord/voltha-go/common/log"
25)
26
27var (
28 RevisionCache = make(map[string]interface{})
29)
30
31type NonPersistedRevision struct {
32 Config *DataRevision
33 Children map[string][]Revision
34 Hash string
35 Branch *Branch
36 WeakRef string
37}
38
39func NewNonPersistedRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
40 cr := &NonPersistedRevision{}
41 cr.Branch = branch
42 cr.Config = NewDataRevision(data)
43 cr.Children = children
44 cr.Finalize()
45
46 return cr
47}
48
49func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
50 npr.Config = config
51}
52
53func (npr *NonPersistedRevision) GetConfig() *DataRevision {
54 return npr.Config
55}
56
57func (npr *NonPersistedRevision) SetChildren(children map[string][]Revision) {
58 npr.Children = children
59}
60
61func (npr *NonPersistedRevision) GetChildren() map[string][]Revision {
62 return npr.Children
63}
64
65func (npr *NonPersistedRevision) SetHash(hash string) {
66 npr.Hash = hash
67}
68
69func (npr *NonPersistedRevision) GetHash() string {
70 return npr.Hash
71}
72
73func (npr *NonPersistedRevision) ClearHash() {
74 npr.Hash = ""
75}
76
77func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
78 npr.Branch = branch
79}
80
81func (npr *NonPersistedRevision) GetBranch() *Branch {
82 return npr.Branch
83}
84
85func (npr *NonPersistedRevision) GetData() interface{} {
86 if npr.Config == nil {
87 return nil
88 }
89 return npr.Config.Data
90}
91
92func (npr *NonPersistedRevision) GetNode() *Node {
93 return npr.Branch.Node
94}
95
96func (npr *NonPersistedRevision) Finalize() {
97 npr.SetHash(npr.hashContent())
98
99 if _, exists := RevisionCache[npr.Hash]; !exists {
100 RevisionCache[npr.Hash] = npr
101 }
102 if _, exists := RevisionCache[npr.Config.Hash]; !exists {
103 RevisionCache[npr.Config.Hash] = npr.Config
104 } else {
105 npr.Config = RevisionCache[npr.Config.Hash].(*DataRevision)
106 }
107}
108
109func (npr *NonPersistedRevision) hashContent() string {
110 var buffer bytes.Buffer
111 var childrenKeys []string
112
113 if npr.Config != nil {
114 buffer.WriteString(npr.Config.Hash)
115 }
116
117 for key, _ := range npr.Children {
118 childrenKeys = append(childrenKeys, key)
119 }
120 sort.Strings(childrenKeys)
121
122 if npr.Children != nil && len(npr.Children) > 0 {
123 // Loop through sorted Children keys
124 for _, key := range childrenKeys {
125 for _, child := range npr.Children[key] {
126 if child != nil && child.GetHash() != "" {
127 buffer.WriteString(child.GetHash())
128 }
129 }
130 }
131 }
132
133 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
134}
135
136func (npr *NonPersistedRevision) Get(depth int) interface{} {
137 originalData := npr.GetData()
138 data := reflect.ValueOf(originalData).Interface()
139
140 if depth != 0 {
141 for fieldName, field := range ChildrenFields(npr.GetData()) {
142 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
143 if field.IsContainer {
144 for _, rev := range npr.Children[fieldName] {
145 childData := rev.Get(depth - 1)
146 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
147 //fmt.Printf("data:%+v, dataHolder:%+v\n", childData, childDataHolder)
148 }
149 } else {
150 rev := npr.Children[fieldName][0]
151 childData := rev.Get(depth - 1)
152 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
153 //fmt.Printf("data:%+v, dataHolder:%+v\n", childData, childDataHolder)
154 }
155 // Merge child data with cloned object
156 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
157 }
158 }
159 return data
160}
161
162func (npr *NonPersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
163 newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
164 newRev.SetBranch(branch)
165 log.Debugf("newRev config : %+v, npr: %+v", newRev.GetConfig(), npr)
166 newRev.SetConfig(NewDataRevision(data))
167 newRev.Finalize()
168
169 return &newRev
170}
171
172func (npr *NonPersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
173 newChildren := make(map[string][]Revision)
174 for entryName, childrenEntry := range npr.Children {
175 for _, revisionEntry := range childrenEntry {
176 newEntry := reflect.ValueOf(revisionEntry).Interface().(Revision)
177 newChildren[entryName] = append(newChildren[entryName], newEntry)
178 }
179 }
180 newChildren[name] = children
181
182 newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
183 newRev.SetBranch(branch)
184 newRev.SetChildren(newChildren)
185 newRev.Finalize()
186
187 return &newRev
188}
189
190func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariee16186c2018-09-11 10:46:34 -0400191 newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400192 newRev.SetBranch(branch)
193 newRev.SetChildren(children)
194 newRev.Finalize()
195
196 return &newRev
197}