Merge "Unit test base"
[dmaap/datarouter.git] / datarouter-node / src / main / java / org / onap / dmaap / datarouter / node / RateLimitedOperation.java
1 /*******************************************************************************
2  * ============LICENSE_START==================================================
3  * * org.onap.dmaap
4  * * ===========================================================================
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * * ===========================================================================
7  * * Licensed under the Apache License, Version 2.0 (the "License");
8  * * you may not use this file except in compliance with the License.
9  * * You may obtain a copy of the License at
10  * *
11  *  *      http://www.apache.org/licenses/LICENSE-2.0
12  * *
13  *  * Unless required by applicable law or agreed to in writing, software
14  * * distributed under the License is distributed on an "AS IS" BASIS,
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * * See the License for the specific language governing permissions and
17  * * limitations under the License.
18  * * ============LICENSE_END====================================================
19  * *
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  * *
22  ******************************************************************************/
23
24
25 package org.onap.dmaap.datarouter.node;
26
27 import java.util.*;
28
29 /**
30  * Execute an operation no more frequently than a specified interval
31  */
32
33 public abstract class RateLimitedOperation implements Runnable {
34     private boolean marked;    // a timer task exists
35     private boolean executing;    // the operation is currently in progress
36     private boolean remark;    // a request was made while the operation was in progress
37     private Timer timer;
38     private long last;    // when the last operation started
39     private long mininterval;
40
41     /**
42      * Create a rate limited operation
43      *
44      * @param mininterval The minimum number of milliseconds after the last execution starts before a new execution can begin
45      * @param timer       The timer used to perform deferred executions
46      */
47     public RateLimitedOperation(long mininterval, Timer timer) {
48         this.timer = timer;
49         this.mininterval = mininterval;
50     }
51
52     private class deferred extends TimerTask {
53         public void run() {
54             execute();
55         }
56     }
57
58     private synchronized void unmark() {
59         marked = false;
60     }
61
62     private void execute() {
63         unmark();
64         request();
65     }
66
67     /**
68      * Request that the operation be performed by this thread or at a later time by the timer
69      */
70     public void request() {
71         if (premark()) {
72             return;
73         }
74         do {
75             run();
76         } while (demark());
77     }
78
79     private synchronized boolean premark() {
80         if (executing) {
81             // currently executing - wait until it finishes
82             remark = true;
83             return (true);
84         }
85         if (marked) {
86             // timer currently running - will run when it expires
87             return (true);
88         }
89         long now = System.currentTimeMillis();
90         if (last + mininterval > now) {
91             // too soon - schedule a timer
92             marked = true;
93             timer.schedule(new deferred(), last + mininterval - now);
94             return (true);
95         }
96         last = now;
97         executing = true;
98         // start execution
99         return (false);
100     }
101
102     private synchronized boolean demark() {
103         executing = false;
104         if (remark) {
105             remark = false;
106             return (!premark());
107         }
108         return (false);
109     }
110 }