Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified throttling/etc/throttling-pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions throttling/etc/throttling-pattern.ucls
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
<class id="1" language="java" name="com.iluwatar.throttling.CallsCount" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java" binary="false" corner="BOTTOM_RIGHT">
<position height="211" width="256" x="656" y="228"/>
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.throttling.Tenant" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/Tenant.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="465" y="524"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.throttling.B2BService" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/B2BService.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="464" y="192"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="4" language="java" name="com.iluwatar.throttling.timer.Throttler" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/timer/Throttler.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="167" y="174"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="5" language="java" name="com.iluwatar.throttling.timer.ThrottleTimerImpl" project="throttling"
file="/throttling/src/main/java/com/iluwatar/throttling/timer/ThrottleTimerImpl.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="166" y="396"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<association id="6">
<end type="SOURCE" refId="3" navigable="false">
<attribute id="7" name="callsCount"/>
<multiplicity id="8" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<dependency id="9">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="4"/>
</dependency>
<dependency id="10">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="2"/>
</dependency>
<association id="11">
<end type="SOURCE" refId="5" navigable="false">
<attribute id="12" name="callsCount"/>
<multiplicity id="13" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<dependency id="14">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="1"/>
</dependency>
<realization id="15">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="4"/>
</realization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>
16 changes: 8 additions & 8 deletions throttling/src/main/java/com/iluwatar/throttling/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ public class App {
* @param args main arguments
*/
public static void main(String[] args) {

Tenant adidas = new Tenant("Adidas", 5);
Tenant nike = new Tenant("Nike", 6);
CallsCount callsCount = new CallsCount();
Tenant adidas = new Tenant("Adidas", 5, callsCount);
Tenant nike = new Tenant("Nike", 6, callsCount);

ExecutorService executorService = Executors.newFixedThreadPool(2);

executorService.execute(() -> makeServiceCalls(adidas));
executorService.execute(() -> makeServiceCalls(nike));
executorService.execute(() -> makeServiceCalls(adidas, callsCount));
executorService.execute(() -> makeServiceCalls(nike, callsCount));

executorService.shutdown();
try {
Expand All @@ -73,9 +73,9 @@ public static void main(String[] args) {
/**
* Make calls to the B2BService dummy API
*/
private static void makeServiceCalls(Tenant tenant) {
Throttler timer = new ThrottleTimerImpl(10);
B2BService service = new B2BService(timer);
private static void makeServiceCalls(Tenant tenant, CallsCount callsCount) {
Throttler timer = new ThrottleTimerImpl(10, callsCount);
B2BService service = new B2BService(timer, callsCount);
for (int i = 0; i < 20; i++) {
service.dummyCustomerApi(tenant);
// Sleep is introduced to keep the output in check and easy to view and analyze the results.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
class B2BService {

private static final Logger LOGGER = LoggerFactory.getLogger(B2BService.class);
private final CallsCount callsCount;

public B2BService(Throttler timer) {
public B2BService(Throttler timer, CallsCount callsCount) {
this.callsCount = callsCount;
timer.start();
}

Expand All @@ -46,13 +48,13 @@ public B2BService(Throttler timer) {
*/
public int dummyCustomerApi(Tenant tenant) {
String tenantName = tenant.getName();
long count = CallsCount.getCount(tenantName);
long count = callsCount.getCount(tenantName);
LOGGER.debug("Counter for {} : {} ", tenant.getName(), count);
if (count >= tenant.getAllowedCallsPerSecond()) {
LOGGER.error("API access per second limit reached for: {}", tenantName);
return -1;
}
CallsCount.incrementCount(tenantName);
callsCount.incrementCount(tenantName);
return getRandomCustomerId();
}

Expand Down
10 changes: 5 additions & 5 deletions throttling/src/main/java/com/iluwatar/throttling/CallsCount.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@
public final class CallsCount {

private static final Logger LOGGER = LoggerFactory.getLogger(CallsCount.class);
private static Map<String, AtomicLong> tenantCallsCount = new ConcurrentHashMap<>();
private Map<String, AtomicLong> tenantCallsCount = new ConcurrentHashMap<>();

/**
* Add a new tenant to the map.
* @param tenantName name of the tenant.
*/
public static void addTenant(String tenantName) {
public void addTenant(String tenantName) {
tenantCallsCount.putIfAbsent(tenantName, new AtomicLong(0));
}

/**
* Increment the count of the specified tenant.
* @param tenantName name of the tenant.
*/
public static void incrementCount(String tenantName) {
public void incrementCount(String tenantName) {
tenantCallsCount.get(tenantName).incrementAndGet();
}

Expand All @@ -61,14 +61,14 @@ public static void incrementCount(String tenantName) {
* @param tenantName name of the tenant.
* @return the count of the tenant.
*/
public static long getCount(String tenantName) {
public long getCount(String tenantName) {
return tenantCallsCount.get(tenantName).get();
}

/**
* Resets the count of all the tenants in the map.
*/
public static void reset() {
public void reset() {
LOGGER.debug("Resetting the map.");
for (Entry<String, AtomicLong> e : tenantCallsCount.entrySet()) {
tenantCallsCount.put(e.getKey(), new AtomicLong(0));
Expand Down
4 changes: 2 additions & 2 deletions throttling/src/main/java/com/iluwatar/throttling/Tenant.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ public class Tenant {
* @param allowedCallsPerSecond The number of calls allowed for a particular tenant.
* @throws InvalidParameterException If number of calls is less than 0, throws exception.
*/
public Tenant(String name, int allowedCallsPerSecond) {
public Tenant(String name, int allowedCallsPerSecond, CallsCount callsCount) {
if (allowedCallsPerSecond < 0) {
throw new InvalidParameterException("Number of calls less than 0 not allowed");
}
this.name = name;
this.allowedCallsPerSecond = allowedCallsPerSecond;
CallsCount.addTenant(name);
callsCount.addTenant(name);
}

public String getName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@
*/
public class ThrottleTimerImpl implements Throttler {

private int throttlePeriod;

public ThrottleTimerImpl(int throttlePeriod) {
private final int throttlePeriod;
private final CallsCount callsCount;

public ThrottleTimerImpl(int throttlePeriod, CallsCount callsCount) {
this.throttlePeriod = throttlePeriod;
this.callsCount = callsCount;
}

/**
Expand All @@ -51,7 +53,7 @@ public void start() {
new Timer(true).schedule(new TimerTask() {
@Override
public void run() {
CallsCount.reset();
callsCount.reset();
}
}, 0, throttlePeriod);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,19 @@
*/
public class B2BServiceTest {

@Disabled
private CallsCount callsCount = new CallsCount();

@Test
public void dummyCustomerApiTest() {
Tenant tenant = new Tenant("testTenant", 2);
Tenant tenant = new Tenant("testTenant", 2, callsCount);
// In order to assure that throttling limits will not be reset, we use an empty throttling implementation
Throttler timer = () -> { };
B2BService service = new B2BService(timer);
B2BService service = new B2BService(timer, callsCount);

for (int i = 0; i < 5; i++) {
service.dummyCustomerApi(tenant);
}
long counter = CallsCount.getCount(tenant.getName());
long counter = callsCount.getCount(tenant.getName());
assertEquals(2, counter, "Counter limit must be reached");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class TenantTest {
@Test
public void constructorTest() {
assertThrows(InvalidParameterException.class, () -> {
Tenant tenant = new Tenant("FailTenant", -1);
Tenant tenant = new Tenant("FailTenant", -1, new CallsCount());
});
}
}