private synchronized Counter getSpecificCounter(final SessionInfo sessionInfo, final SupportedListener listener) { return specificNotifications.computeIfAbsent(listener, key -> new HashMap<>(1)) .computeIfAbsent(sessionInfo, s -> new Counter(s, this.getClass().getSimpleName(), getHourlyLimit(listener))); }
public boolean allow() { return filterValidTimestamps(getTimestamps()).count() < maxItems; } }
public void increase() { final Set<OffsetDateTime> stamps = getTimestamps(); stamps.add(DateUtil.offsetNow()); store(sessionInfo, id, stamps); }
@Test void testTiming() throws InterruptedException { final int seconds = 1; final String id = UUID.randomUUID().toString(); final Counter c = new Counter(SESSION, id, 1, Duration.ofSeconds(seconds)); assertThat(c.allow()).isTrue(); c.increase(); // make sure value was persisted final Counter c2 = new Counter(SESSION, id, 1, Duration.ofSeconds(seconds)); assertThat(c2.allow()).isFalse(); int millis = 0; boolean isAllowed = false; while (millis < seconds * 5 * 1000) { // spend the absolute minimum time waiting Thread.sleep(1); millis += 1; isAllowed = c2.allow(); if (isAllowed) { break; } } if (!isAllowed) { fail("Did not reset counter in time."); } } }
private boolean allowGlobal(final SupportedListener listener, final SessionInfo sessionInfo) { final boolean override = listener.overrideGlobalGag(); return override || getCounter(sessionInfo).allow(); }
public void offer(final Submission s) throws Exception { LOGGER.trace("Received submission."); final SupportedListener listener = s.getSupportedListener(); final SessionInfo session = s.getSessionInfo(); if (!shouldNotify(listener, session)) { LOGGER.debug("Will not notify."); return; } final Map<String, Object> data = s.getData(); LOGGER.trace("Triggering."); send(session, s.getSubject(), s.getMessage(data), s.getFallbackMessage(data)); LOGGER.trace("Triggered."); getSpecificCounter(session, listener).increase(); getCounter(session).increase(); LOGGER.trace("Finished."); }
private void store(final SessionInfo sessionInfo, final String id, final Set<OffsetDateTime> timestamps) { LOGGER.trace("Storing timestamps: {}.", timestamps); TenantState.of(sessionInfo) .in(Counter.class) .reset(b -> b.put(id, filterValidTimestamps(timestamps).map(OffsetDateTime::toString))); }
public Counter(final SessionInfo sessionInfo, final String id, final int maxItems, final Duration period) { this.sessionInfo = sessionInfo; this.id = id; this.maxItems = maxItems; this.period = period; this.timestamps = Reloadable.with(() -> { final Set<OffsetDateTime> result = load(sessionInfo, id); LOGGER.debug("Loaded timestamps: {}.", result); return result; }) .reloadAfter(period) .build(); }
private boolean shouldNotify(final SupportedListener listener, final SessionInfo sessionInfo) { final boolean global = allowGlobal(listener, sessionInfo); return global && getSpecificCounter(sessionInfo, listener).allow(); }
public void offer(final Submission s) throws Exception { LOGGER.trace("Received submission."); final SupportedListener listener = s.getSupportedListener(); final SessionInfo session = s.getSessionInfo(); if (!shouldNotify(listener, session)) { LOGGER.debug("Will not notify."); return; } final Map<String, Object> data = s.getData(); LOGGER.trace("Triggering."); send(session, s.getSubject(), s.getMessage(data), s.getFallbackMessage(data)); LOGGER.trace("Triggered."); getSpecificCounter(session, listener).increase(); getCounter(session).increase(); LOGGER.trace("Finished."); }
private void store(final SessionInfo sessionInfo, final String id, final Set<OffsetDateTime> timestamps) { LOGGER.trace("Storing timestamps: {}.", timestamps); TenantState.of(sessionInfo) .in(Counter.class) .reset(b -> b.put(id, filterValidTimestamps(timestamps).map(OffsetDateTime::toString))); }
public Counter(final SessionInfo sessionInfo, final String id, final int maxItems, final Duration period) { this.sessionInfo = sessionInfo; this.id = id; this.maxItems = maxItems; this.period = period; this.timestamps = Reloadable.with(() -> { final Set<OffsetDateTime> result = load(sessionInfo, id); LOGGER.debug("Loaded timestamps: {}.", result); return result; }) .reloadAfter(period) .build(); }
private synchronized Counter getSpecificCounter(final SessionInfo sessionInfo, final SupportedListener listener) { return specificNotifications.computeIfAbsent(listener, key -> new HashMap<>(1)) .computeIfAbsent(sessionInfo, s -> new Counter(s, this.getClass().getSimpleName(), getHourlyLimit(listener))); }
private boolean allowGlobal(final SupportedListener listener, final SessionInfo sessionInfo) { final boolean override = listener.overrideGlobalGag(); return override || getCounter(sessionInfo).allow(); }
public void increase() { final Set<OffsetDateTime> stamps = getTimestamps(); stamps.add(DateUtil.offsetNow()); store(sessionInfo, id, stamps); }
public boolean allow() { return filterValidTimestamps(getTimestamps()).count() < maxItems; } }
private synchronized Counter getCounter(final SessionInfo sessionInfo) { return notifications.computeIfAbsent(sessionInfo, s -> new Counter(s, "global", getHourlyLimit(), Duration.ofHours(1))); }
private boolean shouldNotify(final SupportedListener listener, final SessionInfo sessionInfo) { final boolean global = allowGlobal(listener, sessionInfo); return global && getSpecificCounter(sessionInfo, listener).allow(); }
private synchronized Counter getCounter(final SessionInfo sessionInfo) { return notifications.computeIfAbsent(sessionInfo, s -> new Counter(s, "global", getHourlyLimit(), Duration.ofHours(1))); }