EPTF_CLL_DsRestAPI_Timeline_Functions.ttcn 32.2 KB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
1
2
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
balaskoa's avatar
balaskoa committed
3
// Copyright (c) 2000-2018 Ericsson Telecom AB                               //
Elemer Lelik's avatar
Elemer Lelik committed
4
5
//                                                                           //
// All rights reserved. This program and the accompanying materials          //
balaskoa's avatar
balaskoa committed
6
// are made available under the terms of the Eclipse Public License v2.0     //
Elemer Lelik's avatar
Elemer Lelik committed
7
// which accompanies this distribution, and is available at                  //
balaskoa's avatar
balaskoa committed
8
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html                                 //
Elemer Lelik's avatar
Elemer Lelik committed
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//  Module: EPTF_CLL_DsRestAPI_Timeline_Functions
// 
//  Purpose:
//    This module contains function definitions for TTCN-3 EPTF DsRestAPI Timeline 
//    implementation.
// 
//  Module Parameters:
//    
//
//  Module depends on:
//    <EPTF_CLL_DataSource_Definitions>
//    <EPTF_CLL_DataSource_Functions>
//
//  Public functions:
//    <f_EPTF_DsRestAPI_Timeline_init_CT>    
// 
//  Current Owner:
//    Daniel Gobor (ednigbo)
// 
//  Last Review Date:
//    
//
//  Detailed Comments:
//    This module contains function definitions for TTCN-3 EPTF DsRestAPI Timeline 
//    implementation.
// 
///////////////////////////////////////////////////////////////////////////////

module EPTF_CLL_DsRestAPI_Timeline_Functions {
  
  import from EPTF_CLL_DataSource_Definitions all;
  import from EPTF_CLL_DataSource_Functions all;
  import from EPTF_CLL_DataSourceClient_Functions all;
  import from EPTF_CLL_DsRestAPI_Timeline_Definitions all;
  import from EPTF_CLL_Logging_Definitions all;
  import from EPTF_CLL_Logging_Functions all;
  import from EPTF_CLL_Base_Functions all;
  import from EPTF_CLL_Variable_Definitions all;
  import from EPTF_CLL_Variable_Functions all;
  import from EPTF_CLL_RBTScheduler_Functions all;
  import from EPTF_CLL_Scheduler_Definitions all;
  import from EPTF_CLL_DsRestAPI_DSServer_Definitions all;
  import from EPTF_CLL_DsRestAPI_DSServer_Functions all;
  import from EPTF_CLL_Common_Definitions all;
  import from TCCFileIO_Functions all;
  
  friend module EPTF_CLL_DsRestAPI_Functions;
  
  ///////////////////////////////////////////////////////////////////////////////
  //  Function: f_EPTF_DsRestAPI_Timeline_init_CT
  // 
  //  Purpose:
  //    Initializes the EPTF_DsRestAPI_Timeline_CT component
  //
  //  Parameters:
  //    pl_selfName - *in* *charstring* - the name of the component
  //
  //  Return Value:
  //    -
  //
  //  Errors:
  //    -
  //
  //  Detailed Comments:
  //    This function should be called before using the <EPTF_DsRestAPI_Timeline_CT> component.
  //    Collection of a timeline begins when a timeline is queried for the first time
  //    using the <c_DsRestAPI_Timeline_dataElementTimeline> dataelement.
  //
  ///////////////////////////////////////////////////////////////////////////////
  public function f_EPTF_DsRestAPI_Timeline_init_CT(in charstring pl_selfName) runs on EPTF_DsRestAPI_Timeline_CT {
    if (v_EPTF_DsRestAPI_Timeline_initialized) {
      return;
    }
  
    f_EPTF_Logging_init_CT(pl_selfName);
    v_DsRestAPI_Timeline_loggingMaskId := f_EPTF_Logging_registerComponentMasks("EPTF_DsRestAPI_Timeline", c_EPTF_DsRestAPI_Timeline_loggingEventClasses, EPTF_Logging_CLL);
  
    f_EPTF_DataSource_init_CT(pl_selfName);
    f_EPTF_DataSourceClient_init_CT(pl_selfName, self);
    
    f_EPTF_Scheduler_init_CT(pl_selfName);
    ef_EPTF_DsRestAPI_Timeline_MapInit();
    
    f_EPTF_DsRestAPI_DSServer_init_CT(pl_selfName);
  
    f_EPTF_DataSourceClient_registerDataValue(c_DsRestAPI_Timeline_DataSource_sourceId, pl_selfName, refers(f_EPTF_DsRestAPI_Timeline_DSProcessDataValue), self);
    f_EPTF_DataSourceClient_registerSetDataValue(c_DsRestAPI_Timeline_DataSource_sourceId, pl_selfName, refers(f_EPTF_DsRestAPI_Timeline_DSProcessSetDataValue), self);
    f_EPTF_DataSourceClient_sendReady(c_DsRestAPI_Timeline_DataSource_sourceId, f_EPTF_Base_selfName());
    
    f_EPTF_Base_registerCleanup(refers(f_EPTF_DsRestAPI_Timeline_cleanup_CT));
    v_EPTF_DsRestAPI_Timeline_initialized := true;
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  //  Function: f_EPTF_DsRestAPI_Timeline_start
  // 
  //  Purpose:
  //    Starts collecting the timeline data.
  //
  //  Parameters:
  //    -
  //
  //  Return Value:
  //    -
  //
  //  Errors:
  //    -
  //
  //  Detailed Comments:
  //    This function should be called to start collecting the timeline data.
  //    When calling this method, appended requests will be sent to the DataSource.
  //    This starts the collection of the contained timeline requests of the appended request.
  //    It is important to call this method only when the appended requests can be queried.
  //    To append a request, the <c_DsRestAPI_Timeline_dataElementAppendFromJSON> and <c_DsRestAPI_Timeline_dataElementAppendFromFile> dataelements can be used.
  //    If DsRestAPI is started with symlink creation, the TimelineRequest.json file will be appended by default.
  //
  ///////////////////////////////////////////////////////////////////////////////
  public function f_EPTF_DsRestAPI_Timeline_start() runs on EPTF_DsRestAPI_Timeline_CT {
    if (v_EPTF_DsRestAPI_Timeline_initialized and not v_DsRestAPI_Timeline_started) {
      f_EPTF_DsRestAPI_Timeline_ScheduleActions();
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_cleanup_CT() runs on EPTF_DsRestAPI_Timeline_CT {
    if (not v_EPTF_DsRestAPI_Timeline_initialized) {
      return;
    }
    f_EPTF_DsRestAPI_Timeline_ClearScheduledActions();
    v_EPTF_DsRestAPI_Timeline_scheduledRequests := {};
    ef_EPTF_DsRestAPI_Timeline_MapCleanup();
    v_EPTF_DsRestAPI_Timeline_initialized := false;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_warning(in @lazy charstring pl_message) runs on EPTF_DsRestAPI_Timeline_CT {
    f_EPTF_Logging_warningV2(pl_message, v_DsRestAPI_Timeline_loggingMaskId, {c_EPTF_DsRestAPI_Timeline_loggingClassIdx_Warning});
  }
  
  private external function ef_DsRestAPI_Timeline_Dec_Requests(in octetstring pl_request) return EPTF_DsRestAPI_Requests with { extension "prototype(convert) decode(JSON)" }
  
  private function f_EPTF_DsRestAPI_Timeline_DSProcessDataValue(
    out EPTF_Var_DirectContent pl_dataValue,
    in charstring pl_source,
    in charstring pl_ptcName,
    in charstring pl_element,
    in EPTF_DataSource_Params pl_params)
  runs on EPTF_DsRestAPI_Timeline_CT return integer {   
    var integer vl_errorCode := -1;
    pl_dataValue := {unknownVal := {omit}};
    select( pl_element )
    {
      case(c_EPTF_DataSource_dataElement_Help) {
        vl_errorCode := f_EPTF_DataSource_handleHelp(pl_dataValue, pl_source, pl_params, c_EPTF_DsRestAPI_Timeline_help);
      }
      case(c_DsRestAPI_Timeline_dataElementTimeline) {
        var charstring vl_key;
        var float vl_period;
        var integer vl_maxpoints;
        var integer vl_since;
        var EPTF_DsRestAPI_Request vl_request;
        f_EPTF_DsRestAPI_Timeline_GetRequestAndKey(pl_params, vl_key, vl_period, vl_maxpoints, vl_since, vl_request);
        var charstring vl_timeline;
        if (ef_EPTF_DsRestAPI_Timeline_GetTimeline(vl_key, vl_since, vl_timeline)) {
          pl_dataValue := {charstringVal := vl_timeline};
          vl_errorCode := 0;
        } else {
          f_EPTF_DsRestAPI_Timeline_AddTimelineToCollect(vl_key, vl_request, vl_period, vl_maxpoints);
          pl_dataValue := {charstringVal := "{\"tp\":0,\"x\":[],\"y\":[]}"};
          vl_errorCode := 0;
        }
      }
      case(c_DsRestAPI_Timeline_dataElementRunning) {
        pl_dataValue := {boolVal := v_DsRestAPI_Timeline_started};
        vl_errorCode := 0;
      }
      case else {}
    }
    return vl_errorCode;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_DSProcessSetDataValue(
    inout EPTF_Var_DirectContent pl_dataValue,
    in charstring pl_source,
    in charstring pl_ptcName,
    in charstring pl_element,
    in EPTF_DataSource_Params pl_params,
    in EPTF_IntegerList pl_indexList)
  runs on EPTF_DsRestAPI_Timeline_CT return integer{   
    var integer vl_errorCode := -1;
    select (pl_element)
    {
      case (c_DsRestAPI_Timeline_dataElementAppendFromFile) {
        if (ischosen(pl_dataValue.charstringVal)) {
          vl_errorCode := f_EPTF_DsRestAPI_Timeline_AppendFromFile(pl_dataValue.charstringVal, pl_dataValue);
        } else {
          pl_dataValue := {charstringVal := "Charstring value expected"};
207
          vl_errorCode := 5;
Elemer Lelik's avatar
Elemer Lelik committed
208
209
210
211
212
213
214
        }
      }
      case (c_DsRestAPI_Timeline_dataElementAppendFromJSON) {
        if (ischosen(pl_dataValue.charstringVal)) {
          vl_errorCode := f_EPTF_DsRestAPI_Timeline_AppendFromJson(char2oct(pl_params[0].paramValue), pl_dataValue);
        } else {
          pl_dataValue := {charstringVal := "Charstring value expected"};
215
          vl_errorCode := 5;
Elemer Lelik's avatar
Elemer Lelik committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
        }
      }
      case (c_DsRestAPI_Timeline_dataElementClear) {
        f_EPTF_DsRestAPI_Timeline_ClearScheduledActions();
        v_EPTF_DsRestAPI_Timeline_scheduledRequests := {};
        ef_EPTF_DsRestAPI_Timeline_MapCleanup();
        ef_EPTF_DsRestAPI_Timeline_MapInit();
        pl_dataValue := {charstringVal := "Clear ok"};
        vl_errorCode := 0;
      }
      case (c_DsRestAPI_Timeline_dataElementRunning) {
        if (ischosen(pl_dataValue.boolVal)) {
          if (v_DsRestAPI_Timeline_started and not pl_dataValue.boolVal) {
            // running and stopped
            f_EPTF_DsRestAPI_Timeline_ClearScheduledActions();
          } else if (not v_DsRestAPI_Timeline_started and pl_dataValue.boolVal) {
            // not running and started
            f_EPTF_DsRestAPI_Timeline_ScheduleActions();
          }
          vl_errorCode := 0;
        } else {
          pl_dataValue := {charstringVal := "Boolean value expected"};
238
          vl_errorCode := 5;
Elemer Lelik's avatar
Elemer Lelik committed
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
        }
      }
      case else {}
    }
    return vl_errorCode;
  }
  
  private external function ef_EPTF_DsRestAPI_Timeline_MapInit();
  private external function ef_EPTF_DsRestAPI_Timeline_MapCleanup();
  private external function ef_EPTF_DsRestAPI_Timeline_InitMeasurement(in charstring pl_key, in integer pl__maxpoints);
  private external function ef_EPTF_DsRestAPI_Timeline_AddMeasurement(in charstring pl_key, in integer pl_time, in charstring pl_content, in integer tp, in integer pl__maxpoints);
  private external function ef_EPTF_DsRestAPI_Timeline_GetTimeline(in charstring pl_key, in integer pl_since, out charstring pl_timeline) return boolean;
  
  private function f_EPTF_DsRestAPI_Timeline_SubscribeHandler(in integer pl_idx, in boolean pl_result, in EPTF_IntegerList pl_argList) runs on EPTF_DsRestAPI_Timeline_CT {
    if (pl_result) {
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_argList[0]].descriptors[pl_argList[1]].varId := pl_idx;
    }
    v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_argList[0]].descriptors[pl_argList[1]].collectionDisabled := false;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_GetDataHandler (
     in charstring pl_source,
     in charstring pl_ptcName,
     in charstring pl_element,
     in EPTF_DataSource_Params pl_params,
     in integer pl_errorCode,
     in charstring pl_remoteDataVarName,
     in EPTF_Var_CT pl_ownerCompRef,
     in integer pl_localDataVarId,
     in EPTF_Var_DirectContent pl_dataValue,
     in EPTF_IntegerList pl_userData
  ) runs on EPTF_DsRestAPI_Timeline_CT {
    if (pl_errorCode == 0) {
      f_EPTF_Var_resubscribeRemote(
        pl_remoteCompRef := pl_ownerCompRef,
        pl_remoteProviderVarName := pl_remoteDataVarName,
        pl_subscriptionMode := sampled,
        pl_idx := pl_localDataVarId,
        pl_localName := "",
        pl_refreshRate := -1,
        pl_respHandler := {refers(f_EPTF_DsRestAPI_Timeline_SubscribeHandler), pl_userData}
      );
    } else {
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].descriptors[pl_userData[1]].collectionDisabled := false;
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_CheckDataHandler (
     in charstring pl_source,
     in charstring pl_ptcName,
     in charstring pl_element,
     in EPTF_DataSource_Params pl_params,
     in integer pl_errorCode,
     in charstring pl_remoteDataVarName,
     in EPTF_Var_CT pl_ownerCompRef,
     in integer pl_localDataVarId,
     in EPTF_Var_DirectContent pl_dataValue,
     in EPTF_IntegerList pl_userData
  ) runs on EPTF_DsRestAPI_Timeline_CT {
    if (pl_errorCode == 0) {
      var EPTF_DsRestAPI_Request vl_request := v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].request[pl_userData[1]];
      f_EPTF_DataSource_getData_nonBlocking(
        vl_request.getData.source,
        vl_request.getData.ptcname,
        vl_request.getData.element,
        vl_request.getData.params,
        {refers(f_EPTF_DsRestAPI_Timeline_GetDataHandler), pl_userData}
      );
    } else {
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].descriptors[pl_userData[1]].collectionDisabled := false;
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_AddTimelineToCollect(in charstring vl_key, in EPTF_DsRestAPI_Request vl_request, in float vl_period, in integer vl_maxpoints) runs on EPTF_DsRestAPI_Timeline_CT {
    var integer vl_requestIndex := f_EPTF_DsRestAPI_Timeline_FindPeriodInRequestList(vl_period);
    var integer vl_nextRequestIndex;
    if (vl_requestIndex != -1) {
      vl_nextRequestIndex := sizeof(v_EPTF_DsRestAPI_Timeline_scheduledRequests[vl_requestIndex].request);
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[vl_requestIndex].request[vl_nextRequestIndex] := vl_request;
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[vl_requestIndex].descriptors[vl_nextRequestIndex] := {-1, vl_key, vl_maxpoints, true};
    } else {
      vl_requestIndex := sizeof(v_EPTF_DsRestAPI_Timeline_scheduledRequests);
      vl_nextRequestIndex := 0;
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[vl_requestIndex] := {
        {vl_request}, {{-1, vl_key, vl_maxpoints, true}}, vl_period, 0, 0, 0, 0
      }
      
      if (v_DsRestAPI_Timeline_started) {
        var float vl_when := f_EPTF_Base_getRelTimeInSecs() + vl_period;
        var integer vl_eventIndex;
        f_EPTF_SchedulerComp_scheduleAction(vl_when, refers(f_EPTF_DsRestAPI_Timeline_IssueRequest), {vl_requestIndex}, vl_eventIndex);
        v_EPTF_DsRestAPI_Timeline_scheduledRequests[vl_requestIndex].eventIndex := vl_eventIndex;
      }
    }
    
    ef_EPTF_DsRestAPI_Timeline_InitMeasurement(vl_key, vl_maxpoints);
    
    f_EPTF_DataSource_checkData_nonblocking(
      vl_request.getData.source,
      vl_request.getData.ptcname,
      vl_request.getData.element,
      vl_request.getData.params,
      {refers(f_EPTF_DsRestAPI_Timeline_CheckDataHandler), {vl_requestIndex, vl_nextRequestIndex}}
    );
  }
  
  private function f_EPTF_DsRestAPI_Timeline_InsertRequestIntoList(in EPTF_DsRestAPI_Requests pl_requestToInsert, inout EPTF_DsRestAPI_Requests pl_requestsToInsertInto, in integer pl_nextIndex, inout EPTF_IntegerList pl_path) {
    if (pl_nextIndex < sizeof(pl_requestToInsert)) {
      var integer vl_indexToInsertInto := sizeof(pl_requestsToInsertInto);
      for (var integer i := 0; i < vl_indexToInsertInto; i := i + 1) {
        if (f_EPTF_DsRestAPI_Timeline_GetDataEquals(pl_requestToInsert[pl_nextIndex].getData, pl_requestsToInsertInto[i].getData)) {
          pl_path[sizeof(pl_path)] := i;
          f_EPTF_DsRestAPI_Timeline_InsertRequestIntoList(pl_requestToInsert, pl_requestsToInsertInto[i].getData.children, pl_nextIndex + 1, pl_path);
          // the same request is already present
          return;
        }
      }
      
      pl_requestsToInsertInto[vl_indexToInsertInto] := pl_requestToInsert[pl_nextIndex];
      pl_path[sizeof(pl_path)] := vl_indexToInsertInto;
      f_EPTF_DsRestAPI_Timeline_InsertRequestIntoList(pl_requestToInsert, pl_requestsToInsertInto[vl_indexToInsertInto].getData.children, pl_nextIndex + 1, pl_path);
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_AppendRequest(in EPTF_DsRestAPI_Request pl_request, in EPTF_DsRestAPI_Requests pl_parentList) runs on EPTF_DsRestAPI_Timeline_CT {
    pl_parentList[sizeof(pl_parentList)] := pl_request;
    var integer vl_parentListSize := sizeof(pl_parentList);
    for (var integer i := 0; i < vl_parentListSize; i := i + 1) {
      pl_parentList[i].getData.children := {};
      f_EPTF_DsRestAPI_Timeline_AddDataElementPresentFilter(pl_parentList[i]);
      pl_parentList[i].getData.rangeFilter := omit;
      pl_parentList[i].getData.writableInfo := omit;
      pl_parentList[i].getData.selectionValues := omit;
    }
    
    var EPTF_IntegerList vl_path := {};
    f_EPTF_DsRestAPI_Timeline_InsertRequestIntoList(pl_parentList, v_startRequest, 0, vl_path);
  }
  
  private function f_EPTF_DsRestAPI_Timeline_CheckAppend(in EPTF_DsRestAPI_Request pl_request, in EPTF_DsRestAPI_Requests pl_parentList) runs on EPTF_DsRestAPI_Timeline_CT {
    if (ischosen(pl_request.getData)) {
      if (ispresent(pl_request.getData.timeline)) {
        f_EPTF_DsRestAPI_Timeline_AppendRequest(pl_request, pl_parentList);
      }
      
      if (ispresent(pl_request.getData.children)) {
        var integer vl_childrenSize := sizeof(pl_request.getData.children);
        var integer vl_nextParentIndex := sizeof(pl_parentList);
        for (var integer i := 0; i < vl_childrenSize; i := i + 1) {
          pl_parentList[vl_nextParentIndex] := pl_request;
          f_EPTF_DsRestAPI_Timeline_CheckAppend(pl_request.getData.children[i], pl_parentList);
        }
      }
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_AppendRequests(in EPTF_DsRestAPI_Requests pl_requests) runs on EPTF_DsRestAPI_Timeline_CT {
    var integer vl_requestLength := sizeof(pl_requests);
    for (var integer i := 0; i < vl_requestLength; i := i + 1) {
      f_EPTF_DsRestAPI_Timeline_CheckAppend(pl_requests[i], {});
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_AppendFromJson(in octetstring pl_jsonRequest, out EPTF_Var_DirectContent pl_dataValue) runs on EPTF_DsRestAPI_Timeline_CT return integer {
    @try {
      var EPTF_DsRestAPI_Requests vl_request := ef_DsRestAPI_Timeline_Dec_Requests(pl_jsonRequest);
      f_EPTF_DsRestAPI_Timeline_AppendRequests(vl_request);
      if (v_DsRestAPI_Timeline_started and sizeof(v_startRequest) > 0) {
        f_EPTF_DsRestAPI_DSServer_processRequest(v_startRequest);
        v_startRequest := {};
      }
      pl_dataValue := {charstringVal := "Append ok"};
      return 0;
    } @catch(dte_str) {
      pl_dataValue := {charstringVal := "Appending the request failed: "& dte_str};
      return -2;
    }
  }
  
  friend function f_EPTF_DsRestAPI_Timeline_AppendFromFile(in charstring pl_fileName, out EPTF_Var_DirectContent pl_dataValue) runs on EPTF_DsRestAPI_Timeline_CT return integer {
    var integer vl_errorCode := -1;
    var integer vl_file := f_FIO_open_rdonly(pl_fileName);
    if (vl_file != -1) {
      var integer vl_bufferSize := f_FIO_seek_end(vl_file);
      if (vl_bufferSize != -1 and f_FIO_seek_home(vl_file) != -1) {
        var octetstring vl_requestInFile;
        if (f_FIO_read_data(vl_file, vl_requestInFile, vl_bufferSize) != -1) {
          vl_errorCode := f_EPTF_DsRestAPI_Timeline_AppendFromJson(vl_requestInFile, pl_dataValue);
        } else {
          pl_dataValue := {charstringVal := "Reading the file failed."};
          vl_errorCode := -3;
        }
      } else {
        pl_dataValue := {charstringVal := "Reading the file failed."};
        vl_errorCode := -3;
      }
    } else {
      pl_dataValue := {charstringVal := "Opening file " & pl_fileName & " failed."};
      vl_errorCode := -4;
    }
    return vl_errorCode;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_AddDataElementPresentFilter(inout EPTF_DsRestAPI_Request pl_request) {
    pl_request.getData.filter := {request := {
      source := c_EPTF_DataSource_sourceId,
      ptcname := omit,
      element := c_EPTF_DataSource_condition_dataElementPresent,
      params := {{
        paramName := c_EPTF_DataSource_paramNameSource,
        paramValue := {dataValue := pl_request.getData.source}
      }, {
        paramName := c_EPTF_DataSource_paramNameElement,
        paramValue := {dataValue := pl_request.getData.element}
      }}
    }};
    if (ispresent(pl_request.getData.ptcname)) {
      pl_request.getData.filter.request.params[sizeof(pl_request.getData.filter.request.params)] := {
        paramName := c_EPTF_DataSource_paramNamePTCName,
        paramValue := {dataValue := pl_request.getData.ptcname}
      }
    }
    if (ispresent(pl_request.getData.params)) {
      for (var integer i := 0; i < sizeof(pl_request.getData.params); i := i + 1) {
        pl_request.getData.filter.request.params[sizeof(pl_request.getData.filter.request.params)] := {
          paramName := c_EPTF_DataSource_paramNameParamName,
          paramValue := {dataValue := pl_request.getData.params[i].paramName}
        }
        pl_request.getData.filter.request.params[sizeof(pl_request.getData.filter.request.params)] := {
          paramName := c_EPTF_DataSource_paramNameParamValue,
          paramValue := {dataValue := pl_request.getData.params[i].paramValue}
        }
      }
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_GetDataEquals(in EPTF_DsRestAPI_GetData pl_getData1, in EPTF_DsRestAPI_GetData pl_getData2) return boolean {
    if (pl_getData1.source != pl_getData2.source or pl_getData1.element != pl_getData2.element) {
      return false;
    }
    
    if (
      (ispresent(pl_getData1.ptcname) and not ispresent(pl_getData2.ptcname)) or
      (not ispresent(pl_getData1.ptcname) and ispresent(pl_getData2.ptcname)) or
      (ispresent(pl_getData1.ptcname) and ispresent(pl_getData2.ptcname) and pl_getData1.ptcname == pl_getData2.ptcname)
    ) {
      return false;
    }
    
    if (
      (ispresent(pl_getData1.params) and not ispresent(pl_getData2.params)) or
      (not ispresent(pl_getData1.params) and ispresent(pl_getData2.params)) or
      (ispresent(pl_getData1.params) and ispresent(pl_getData2.params) and sizeof(pl_getData1.params) != sizeof(pl_getData2.params))
    ) {
      return false;
    }
    
    if (ispresent(pl_getData1.params) and ispresent(pl_getData2.params)) {
      var integer vl_size := sizeof(pl_getData1.params);
      for (var integer i := 0; i < vl_size; i := i + 1) {
        if (pl_getData1.params[i] != pl_getData2.params[i]) {
          return false;
        }
      }
    }
    
    return true;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_FindPeriodInRequestList(in float pl_period) runs on EPTF_DsRestAPI_Timeline_CT return integer {
    var integer vl_index := -1;
    for (var integer i := 0; i < sizeof(v_EPTF_DsRestAPI_Timeline_scheduledRequests); i := i + 1) {
      if (v_EPTF_DsRestAPI_Timeline_scheduledRequests[i].period == pl_period and sizeof(v_EPTF_DsRestAPI_Timeline_scheduledRequests[i].request) < c_DsRestAPI_Timeline_maxRequestSize) {
        vl_index := i;
        break;
      }
    }
    return vl_index;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_ClearScheduledActions() runs on EPTF_DsRestAPI_Timeline_CT {
    for (var integer i := 0; i < sizeof(v_EPTF_DsRestAPI_Timeline_scheduledRequests); i := i + 1) {
      f_EPTF_SchedulerComp_CancelEvent(v_EPTF_DsRestAPI_Timeline_scheduledRequests[i].eventIndex);
    }
    v_DsRestAPI_Timeline_started := false;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_ScheduleActions() runs on EPTF_DsRestAPI_Timeline_CT {
    if (sizeof(v_startRequest) > 0) {
      f_EPTF_DsRestAPI_DSServer_processRequest(v_startRequest);
      v_startRequest := {};
    }
    
    var float vl_now := f_EPTF_Base_getRelTimeInSecs();
    for (var integer i := 0; i < sizeof(v_EPTF_DsRestAPI_Timeline_scheduledRequests); i := i + 1) {
      var float vl_when := vl_now + v_EPTF_DsRestAPI_Timeline_scheduledRequests[i].period;
      var integer vl_eventIndex;
      f_EPTF_SchedulerComp_scheduleAction(vl_when, refers(f_EPTF_DsRestAPI_Timeline_IssueRequest), {i}, vl_eventIndex);
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[i].eventIndex := vl_eventIndex;
    }
    v_DsRestAPI_Timeline_started := true;
  }
  
  private function f_EPTF_DsRestAPI_Timeline_AddTimelineData(
    in EPTF_DsRestAPI_Content pl_response,
    in EPTF_CLL_DsRestAPI_Timeline_SceduledRequestDescriptor pl_descriptor,
    in integer pl_time
  ) {
    var charstring vl_key := pl_descriptor.key;
    var charstring vl_contentAsString;
    var integer vl_contentType;
    f_EPTF_DsRestAPI_Timeline_ConvertContentToString(pl_response, vl_contentAsString, vl_contentType);
    ef_EPTF_DsRestAPI_Timeline_AddMeasurement(vl_key, pl_time, vl_contentAsString, vl_contentType, pl_descriptor.maxpoints);
  }
  
  private function f_EPTF_DsRestAPI_Timeline_ConvertContentToString(in EPTF_DsRestAPI_Content pl_content, out charstring pl_contentAsString, out integer pl_contentType) {
    if (ischosen(pl_content.node)) {
      pl_contentAsString := pl_content.node.val;
      pl_contentType := pl_content.node.tp;
    } else /*if (ischosen(pl_content.list))*/ {
      var integer vl_listSize := sizeof(pl_content.list);
      if (vl_listSize == 0) {
        pl_contentAsString := "[]";
        pl_contentType := 0;
      } else {
        pl_contentType := pl_content.list[0].node.tp;
        pl_contentAsString := "[" & pl_content.list[0].node.val;
        for (var integer i := 1; i < vl_listSize; i := i + 1) {
          pl_contentAsString := pl_contentAsString & "," & pl_content.list[i].node.val;
        }
        pl_contentAsString := pl_contentAsString & "]";
      }
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_GetRequestAndKey(in EPTF_DataSource_Params pl_params, out charstring pl_key, out float pl_period, out integer pl_maxpoints, out integer pl_since, out EPTF_DsRestAPI_Request pl_request) {
    pl_period := c_DsRestAPI_Timeline_period;
    pl_maxpoints := c_DsRestAPI_Timeline_maxpoints;
    pl_since := -1;
    
    pl_request := {
      getData := {
        source := "",
        ptcname := "",
        element := "",
        params := {},
        cookie := omit,
        children := omit,
        filter := omit,
        rangeFilter := omit,
        selection := omit,
        selectionValues := omit,
        writableInfo := omit,
        timeline := omit
      }
    }
    
    var integer vl_nextParamIndex := 0;
    var integer vl_paramsLength := sizeof(pl_params);
    for (var integer i := 0; i < vl_paramsLength; i := i + 1) {
      if (pl_params[i].paramName == c_DsRestAPI_Timeline_paramNamePeriod) {
        pl_period := str2float(pl_params[i].paramValue);
      }
      if (pl_params[i].paramName == c_DsRestAPI_Timeline_paramNameMaxpoints) {
        pl_maxpoints := str2int(pl_params[i].paramValue);
      }
      if (pl_params[i].paramName == c_DsRestAPI_Timeline_paramNameSince) {
        pl_since := str2int(pl_params[i].paramValue);
      }
      if (pl_params[i].paramName == c_EPTF_DataSource_paramNameSource) {
        pl_key := pl_params[i].paramValue;
        pl_request.getData.source := pl_params[i].paramValue;
      }
      if (pl_params[i].paramName == c_EPTF_DataSource_paramNamePTCName and pl_params[i].paramValue != "") {
        pl_key := pl_key & "." & pl_params[i].paramValue;
        pl_request.getData.ptcname := pl_params[i].paramValue;
      }
      if (pl_params[i].paramName == c_EPTF_DataSource_paramNameElement) {
        pl_key := pl_key & "." & pl_params[i].paramValue;
        pl_request.getData.element := pl_params[i].paramValue;
      }
      if (pl_params[i].paramName == c_EPTF_DataSource_paramNameParamName) {
        pl_key := pl_key & "." & pl_params[i].paramValue;
        if (isbound(pl_request.getData.params[vl_nextParamIndex])) {
          pl_request.getData.params[vl_nextParamIndex].paramName := pl_params[i].paramValue;
        } else {
          pl_request.getData.params[vl_nextParamIndex] := {pl_params[i].paramValue, ""};
        }
      }
      if (pl_params[i].paramName == c_EPTF_DataSource_paramNameParamValue) {
        pl_key := pl_key & ":" & pl_params[i].paramValue;
        if (isbound(pl_request.getData.params[vl_nextParamIndex])) {
          pl_request.getData.params[vl_nextParamIndex].paramValue := pl_params[i].paramValue;
        } else {
          pl_request.getData.params[vl_nextParamIndex] := {"", pl_params[i].paramValue};
        }
        vl_nextParamIndex := vl_nextParamIndex + 1;
      }
    }
    pl_key := pl_key & ".." & float2str(pl_period) & "." & int2str(pl_maxpoints);
  }
  
  private function f_EPTF_DsRestAPI_Timeline_TryToScheduleNewReuqest(in integer pl_index) runs on EPTF_DsRestAPI_Timeline_CT {
    if (v_DsRestAPI_Timeline_started and v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_index].responsesReceived == v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_index].responsesExpected) {
      var float vl_when := f_EPTF_Base_getRelTimeInSecs() + v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_index].period;
      var integer vl_eventIndex;
      f_EPTF_SchedulerComp_scheduleAction(vl_when, refers(f_EPTF_DsRestAPI_Timeline_IssueRequest), {pl_index}, vl_eventIndex);
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_index].eventIndex := vl_eventIndex;
    }
  }
  
  private function f_EPTF_DsRestAPI_Timeline_ResponseArrived(in integer pl_errorCode, in EPTF_Var_DirectContent pl_dataValue, in EPTF_IntegerList pl_userData) runs on EPTF_DsRestAPI_Timeline_CT {
    if (pl_errorCode == 0) {
      var EPTF_DsRestAPI_Content vl_content := f_EPTF_DsRestAPI_DSServer_getContentFromDataValue(pl_dataValue);
      f_EPTF_DsRestAPI_Timeline_AddTimelineData(
        vl_content,
        v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].descriptors[pl_userData[1]],
        v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].lastMeasurement
      );
    } else {
      v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].descriptors[pl_userData[1]].collectionDisabled := true;
      f_EPTF_DsRestAPI_Timeline_warning("Timeline collection disabled for " & log2str(v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].request[pl_userData[1]]) & "; Reason: " & log2str(pl_dataValue));
    }
    
    v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].responsesReceived := v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_userData[0]].responsesReceived + 1;
    f_EPTF_DsRestAPI_Timeline_TryToScheduleNewReuqest(pl_userData[0]);
  }
  
  private function f_EPTF_DsRestAPI_Timeline_IssueRequest(in EPTF_ScheduledAction pl_action, in integer pl_eventIndex) runs on EPTF_DsRestAPI_Timeline_CT return boolean {
    var integer vl_numberOfRequests := sizeof(v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].request);
    v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].responsesReceived := 0;
    v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].responsesExpected := vl_numberOfRequests;
    v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].lastMeasurement := float2int(f_EPTF_Base_getAbsTimeInSecs());
    for (var integer i := 0; i < vl_numberOfRequests; i := i + 1) {
      if (v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].descriptors[i].collectionDisabled) {
        v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].responsesReceived := v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].responsesReceived + 1;
        f_EPTF_DsRestAPI_Timeline_TryToScheduleNewReuqest(pl_action.actionId[0]);
      } else if (v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].descriptors[i].varId == -1) {
        if (0 != f_EPTF_DataSource_getDataValue_nonblocking(
          v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].request[i].getData.source,
          v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].request[i].getData.ptcname,
          v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].request[i].getData.element,
          v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].request[i].getData.params, {rangeFilter := omit},
          {
            refers(f_EPTF_DsRestAPI_Timeline_ResponseArrived),
            {pl_action.actionId[0], i}
          }
        )) {
          v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].descriptors[i].collectionDisabled := true;
        }
      } else {
        var EPTF_Var_DirectContent vl_content;
        f_EPTF_Var_getContent(v_EPTF_DsRestAPI_Timeline_scheduledRequests[pl_action.actionId[0]].descriptors[i].varId, vl_content);
        f_EPTF_DsRestAPI_Timeline_ResponseArrived(0, vl_content, {pl_action.actionId[0], i});
      }
    }
    
    return true;
  }
698
}