RICPLT-2801 Implement Subscription Request timer, RICPLT-2801 Implement Subscription Delete Request timer, add handler call for Subscription Delete Failure and update RMR library and xapp_frame versions

Change-Id: Ib1610cfa806d38bff7dc0ebad8f0b599a0919d34
Signed-off-by: Anssi Mannila <anssi.mannila@nokia.com>
diff --git a/pkg/control/timer.go b/pkg/control/timer.go
new file mode 100644
index 0000000..5d48464
--- /dev/null
+++ b/pkg/control/timer.go
@@ -0,0 +1,170 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+Timer takes four parameters:
+	 1) strId 			string   			'string format timerMap key'
+	 2) nbrId 			int      			'numeric format timerMap key'
+	 3) timerDuration	time.Duration  		'timer duration'
+	 4) timerFunction	func(string, int) 	'function to be executed when timer expires'
+
+	Timer function is put inside in-build time.AfterFunc() Go function, where it is run inside own Go routine
+	when the timer expires. Timer are two key values. Both are used always, but the other one can be left
+	"empty", i.e. strId = "" or  nbrId = 0. Fourth parameter, the timer function is bare function name without
+	any function parameters and parenthesis! Filling first parameter strId with related name can improve
+	code readability and robustness, even the numeric Id would be enough from functionality point of view.
+
+	TimerStart() function starts the timer. If TimerStart() function is called again with same key values
+	while earlier started timer is still in the timerMap, i.e. it has not been stopped or the timer has not
+	yet expired, the old timer is deleted and new timer is started with the given time value.
+
+	StopTimer() function stops the timer. There is no need to call StopTimer() function after the timer has
+	expired. Timer is removed automatically from the timeMap. Calling StopTimer() function with key values not
+	existing in the timerMap, has no effect.
+
+	NOTE: Each timer is run in separate Go routine. Therefore, the function that is executed when timer expires
+	MUST be designed to be able run concurrently! Also, function run order of simultaneously expired timers cannot
+	guaranteed anyway!
+
+	If you need to transport more information to the timer function, consider to use another map to store the
+	information with same key value, as the started timer.
+
+	Init timerMap example:
+		timerMap := new(TimerMap)
+		timerMap.Init()
+
+	StartTimer() and StartTimer() function usage examples.
+	1)
+		subReqTime := 2 * time.Second
+		subId := 123
+		timerMap.StartTimer("RIC_SUB_REQ", int(subId), subReqTime, handleSubscriptionRequestTimer)
+		timerMap.StopTimer("RIC_SUB_REQ", int(subId))
+		
+	2)
+		subReqTime := 2 * time.Second
+		strId := "1UHSUwNqxiVgUWXvC4zFaatpZFF"
+		timerMap.StartTimer(strId, 0, subReqTime, handleSubscriptionRequestTimer)
+		timerMap.StopTimer(strId, 0)
+
+	3)
+		subReqTime := 2 * time.Second
+		strId := "1UHSUwNqxiVgUWXvC4zFaatpZFF"
+		timerMap.StartTimer(RIC_SUB_REQ_" + strId, 0, subReqTime, handleSubscriptionRequestTimer)
+		timerMap.timerMap.StopTimer("RIC_SUB_REQ_" + strId, 0)
+
+	Timer function example. This is run if any of the above started timer expires.
+		func handleSubscriptionRequestTimer1(strId string, nbrId int) {
+			fmt.Printf("Subscription Request timer expired. Name: %v, SubId: %v\n",strId, nbrId)
+		}
+*/
+
+package control
+
+import (
+	"gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
+	"sync"
+	"time"
+)
+
+type TimerKey struct {
+	strId  string
+	nbrId  int
+}
+
+type TimerInfo struct {
+	timerAddress *time.Timer	
+	timerFunctionAddress func()
+}
+
+type TimerMap struct {
+	timer map[TimerKey] TimerInfo
+	mutex sync.Mutex
+}
+
+// This method should run as a constructor
+func (t *TimerMap) Init() {
+	t.timer = make(map[TimerKey] TimerInfo)
+}
+
+func (t *TimerMap) StartTimer(strId string, nbrId int, expireAfterTime time.Duration, timerFunction func(srtId string, nbrId int)) bool {
+	t.mutex.Lock()
+	defer t.mutex.Unlock()
+	if (timerFunction == nil) {
+		xapp.Logger.Error("StartTimer() timerFunc == nil\n")
+		return false
+	}
+	timerKey := TimerKey{strId, nbrId}
+	// Stop timer if there is already timer running with the same id
+	if val, ok := t.timer[timerKey]; ok {
+		xapp.Logger.Debug("StartTimer() old timer found")
+		if val.timerAddress != nil {
+			xapp.Logger.Debug("StartTimer() deleting old timer")
+			val.timerAddress.Stop()
+		}
+		delete(t.timer, timerKey)
+	}
+
+	// Store in timerMap in-build Go "timer", timer function executor, and the function to be executed when the timer expires
+	t.timer[timerKey] = TimerInfo{timerAddress: time.AfterFunc(expireAfterTime, func(){t.timerFunctionExecutor(strId,nbrId)}),
+					    timerFunctionAddress: func(){timerFunction(strId,nbrId)}}
+	return true
+}
+
+func (t *TimerMap) StopTimer(strId string, nbrId int) bool {
+	t.mutex.Lock()
+	defer t.mutex.Unlock()
+	timerKey := TimerKey{strId, nbrId}
+	if val, ok := t.timer[timerKey]; ok {
+		if val.timerAddress != nil {
+			val.timerAddress.Stop()
+			delete(t.timer, timerKey)
+			return true
+		} else {
+			xapp.Logger.Error("StopTimer() timerAddress == nil")
+			return false
+		}
+	} else {
+		xapp.Logger.Debug("StopTimer() Timer not found. May be expired or stopped already. timerKey.strId: %v, timerKey.strId: %v\n", timerKey.strId, timerKey.nbrId)
+		return false
+	}
+}
+
+func (t *TimerMap) timerFunctionExecutor(strId string, nbrId int) {
+	t.mutex.Lock()
+	timerKey := TimerKey{strId, nbrId}
+	if val, ok := t.timer[timerKey]; ok {
+		if val.timerFunctionAddress != nil {
+			// Take local copy of timer function address
+			f := val.timerFunctionAddress
+			// Delete timer instance from map
+			delete(t.timer, timerKey)
+			t.mutex.Unlock()
+			// Execute the timer function
+			f()
+			return
+		} else {
+			xapp.Logger.Error("timerExecutorFunc() timerFunctionAddress == nil")
+			t.mutex.Unlock()
+			return
+		}
+	} else {
+		xapp.Logger.Error("timerExecutorFunc() Timer is not anymore in map. timerKey.strId: %v, timerKey.strId: %v\n", timerKey.strId, timerKey.nbrId)
+		t.mutex.Unlock()
+		return
+	}
+}