Remove major and minor code smells in dr-node
[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.Timer;
28 import java.util.TimerTask;
29
30 /**
31  * Execute an operation no more frequently than a specified interval
32  */
33
34 public abstract class RateLimitedOperation implements Runnable {
35
36     private boolean marked;    // a timer task exists
37     private boolean executing;    // the operation is currently in progress
38     private boolean remark;    // a request was made while the operation was in progress
39     private Timer timer;
40     private long last;    // when the last operation started
41     private long mininterval;
42
43     /**
44      * Create a rate limited operation
45      *
46      * @param mininterval The minimum number of milliseconds after the last execution starts before a new execution can
47      * begin
48      * @param timer The timer used to perform deferred executions
49      */
50     public RateLimitedOperation(long mininterval, Timer timer) {
51         this.timer = timer;
52         this.mininterval = mininterval;
53     }
54
55     /**
56      * Request that the operation be performed by this thread or at a later time by the timer
57      */
58     public void request() {
59         if (premark()) {
60             return;
61         }
62         do {
63             run();
64         } while (demark());
65     }
66
67     private synchronized boolean premark() {
68         if (executing) {
69             // currently executing - wait until it finishes
70             remark = true;
71             return (true);
72         }
73         if (marked) {
74             // timer currently running - will run when it expires
75             return (true);
76         }
77         long now = System.currentTimeMillis();
78         if (last + mininterval > now) {
79             // too soon - schedule a timer
80             marked = true;
81             timer.schedule(new Deferred(), last + mininterval - now);
82             return (true);
83         }
84         last = now;
85         executing = true;
86         // start execution
87         return (false);
88     }
89
90     private synchronized boolean demark() {
91         executing = false;
92         if (remark) {
93             remark = false;
94             return (!premark());
95         }
96         return (false);
97     }
98
99     private class Deferred extends TimerTask {
100
101         public void run() {
102             execute();
103         }
104
105         private void execute() {
106             unmark();
107             request();
108         }
109
110         private synchronized void unmark() {
111             marked = false;
112         }
113     }
114 }