aboutsummaryrefslogtreecommitdiffstats
path: root/lib/rlock/src/main/java/org/onap/ccsdk/features/lib/rlock/SynchronizedFunction.java
blob: 4199778904d937a0b74749120b07c462887ded05 (plain)
1
2
3
4
5
6
7
8
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
package org.onap.ccsdk.features.lib.rlock;

import java.security.SecureRandom;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * <p>
 * A simple abstract base class, providing functionality similar to the <tt>synchronized</tt> block
 * in Java. Derived class provides the set of resources that need synchronized access and the
 * processing method that is executed while the set of resources is locked (override <tt>_exec</tt>
 * method). This class uses the {@link LockHelper} service to lock the resources, execute the
 * processing method and then unlock the resources.
 * </p>
 * <p>
 * Example:
 * </p>
 *
 * <pre style="color:darkblue;">
 * public class BandwidthCheckFunction extends SynchronizedFunction {
 *
 *     private PortBandwidthDao portBandwidthDao;
 *     private int neededBandwidth;
 *     private int bandwidthLimit;
 *
 *     private boolean successful; // Output
 *
 *     public BandwidthCheckFunction(LockHelper lockHelper, PortBandwidthDao portBandwidthDao, String portId,
 *             int neededBandwidth, int bandwidthLimit) {
 *         super(lockHelper, Collections.singleton(portId + "-Bandwidth"), 60); // 60 sec lockTimeout
 *         this.portBandwidthDao = portBandwidthDao;
 *         this.neededBandwidth = neededBandwidth;
 *         this.bandwidthLimit = bandwidthLimit;
 *     }
 *
 *     {@literal @}Override
 *     protected void _exec() {
 *         int usedBandwidth = portBandwidthDao.readUsedBandwidth("Port-123");
 *         if (usedBandwidth + neededBandwidth <= bandwidthLimit) {
 *             portBandwidthDao.updateUsedBandwidth("Port-123", usedBandwidth + neededBandwidth);
 *             successful = true;
 *         } else {
 *             successful = false;
 *         }
 *     }
 *
 *     public boolean isSuccessful() {
 *         return successful;
 *     }
 * }
 *
 * ..........
 *
 *     BandwidthCheckFunction func = new BandwidthCheckFunction(lockHelper, portBandwidthDao, "Port-123", 100, 1000);
 *     func.exec();
 *     boolean success = func.isSuccessful();
 * ..........
 * </pre>
 *
 * @see LockHelper
 */
public abstract class SynchronizedFunction {

    private Set<String> syncSet;
    private String lockRequester;
    private int lockTimeout; // Seconds
    private LockHelper lockHelper;

    /**
     * @param lockHelper {@link LockHelper} service implementation
     * @param syncSet the set of resources to be locked during processing
     * @param lockTimeout the lock expiration timeout (see {@link LockHelper#lock(String, String, int)
     *        LockHelper.lock})
     */
    protected SynchronizedFunction(LockHelper lockHelper, Collection<String> syncSet, int lockTimeout) {
        this.lockHelper = lockHelper;
        this.syncSet = new HashSet<>(syncSet);
        lockRequester = generateLockRequester();
        this.lockTimeout = lockTimeout;
    }

    /**
     * Implement this method with the required processing. This method is executed while the resources
     * are locked (<tt>syncSet</tt> provided in the constructor).
     */
    protected abstract void _exec();

    /**
     * Call this method to execute the provided processing in the derived class (the implemented
     * <tt>_exec</tt> method).
     */
    public void exec() {
        lockHelper.lock(syncSet, lockRequester, lockTimeout);
        try {
            _exec();
        } finally {
            lockHelper.unlock(syncSet, true);
        }
    }

    private static String generateLockRequester() {
        SecureRandom random = new SecureRandom();
        return "SynchronizedFunction-" + (random.nextInt() % 1000000);
    }
}