Skip to content

Commit

Permalink
[Ref] Remove ConfigParam enum, use just constants.
Browse files Browse the repository at this point in the history
Fix Javadoc reference issues.
  • Loading branch information
ledsoft committed Sep 16, 2024
1 parent ff53cfc commit 270dc1b
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 86 deletions.
17 changes: 9 additions & 8 deletions src/main/java/cz/cvut/kbss/termit/config/WebAppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import cz.cvut.kbss.jsonld.jackson.serialization.SerializationConstants;
import cz.cvut.kbss.termit.rest.servlet.DiagnosticsContextFilter;
import cz.cvut.kbss.termit.util.AdjustedUriTemplateProxyServlet;
import cz.cvut.kbss.termit.util.ConfigParam;
import cz.cvut.kbss.termit.util.Constants;
import cz.cvut.kbss.termit.util.json.MultilingualStringDeserializer;
import cz.cvut.kbss.termit.util.json.MultilingualStringSerializer;
Expand Down Expand Up @@ -137,8 +136,10 @@ public ServletWrappingController sparqlEndpointController() throws Exception {
final cz.cvut.kbss.termit.util.Configuration.Repository repository = config.getRepository();
p.setProperty("targetUri", repository.getUrl());
p.setProperty("log", "false");
p.setProperty(ConfigParam.REPO_USERNAME.toString(), repository.getUsername() != null ? repository.getUsername() : "");
p.setProperty(ConfigParam.REPO_PASSWORD.toString(), repository.getPassword() != null ? repository.getPassword() : "");
p.setProperty(AdjustedUriTemplateProxyServlet.REPO_USERNAME_PARAM,
repository.getUsername() != null ? repository.getUsername() : "");
p.setProperty(AdjustedUriTemplateProxyServlet.REPO_PASSWORD_PARAM,
repository.getPassword() != null ? repository.getPassword() : "");
controller.setInitParameters(p);
controller.afterPropertiesSet();
return controller;
Expand All @@ -149,7 +150,7 @@ public SimpleUrlHandlerMapping sparqlQueryControllerMapping() throws Exception {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(0);
final Map<String, Object> urlMap = Collections.singletonMap(Constants.REST_MAPPING_PATH + "/query",
sparqlEndpointController());
sparqlEndpointController());
mapping.setUrlMap(urlMap);
return mapping;
}
Expand Down Expand Up @@ -195,10 +196,10 @@ public FilterRegistrationBean<DiagnosticsContextFilter> mdcFilter() {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI().components(new Components().addSecuritySchemes("bearer-key",
new SecurityScheme().type(
SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")))
new SecurityScheme().type(
SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")))
.info(new Info().title("TermIt REST API").description("TermIt REST API definition.")
.version(version));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,21 @@
*/
public class AdjustedUriTemplateProxyServlet extends URITemplateProxyServlet {

/**
* Configuration parameter representing username to use when connecting to the repository.
*/
public static final String REPO_USERNAME_PARAM = "repository.username";
/**
* Configuration parameter representing password to use when connecting to the repository.
*/
public static final String REPO_PASSWORD_PARAM = "repository.password";

@Override
protected void service(HttpServletRequest servletRequest,
HttpServletResponse servletResponse)
throws ServletException, IOException {
final String username = getConfigParam(ConfigParam.REPO_USERNAME.toString());
final String password = getConfigParam(ConfigParam.REPO_PASSWORD.toString());
final String username = getConfigParam(REPO_USERNAME_PARAM);
final String password = getConfigParam(REPO_PASSWORD_PARAM);
super.service(new AuthenticatingServletRequestWrapper(servletRequest, username, password),
new HttpServletResponseWrapper(servletResponse) {
@Override
Expand Down
45 changes: 0 additions & 45 deletions src/main/java/cz/cvut/kbss/termit/util/ConfigParam.java

This file was deleted.

1 change: 0 additions & 1 deletion src/main/java/cz/cvut/kbss/termit/util/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ public class Configuration {
* After how much time, should objects with completed futures be discarded.
* The value must be positive ({@code > 0}).
* @configurationdoc.default 1 minute
* @see ThrottleAspect#clearOldFutures()
*/
private Duration throttleDiscardThreshold = Duration.ofMinutes(1);

Expand Down
2 changes: 0 additions & 2 deletions src/main/java/cz/cvut/kbss/termit/util/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
package cz.cvut.kbss.termit.util;

import cz.cvut.kbss.jopa.vocabulary.SKOS;
import cz.cvut.kbss.termit.util.throttle.ThrottleAspect;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
Expand Down
69 changes: 41 additions & 28 deletions src/main/java/cz/cvut/kbss/termit/util/throttle/ThrottleAspect.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_SINGLETON;

/**
* @see Throttle
* @implNote The aspect is configured in {@code spring-aop.xml}, this uses Spring AOP instead of AspectJ.
* @see Throttle
*/
@Order
@Scope(SCOPE_SINGLETON)
Expand All @@ -80,22 +80,21 @@ public class ThrottleAspect extends LongRunningTaskScheduler {

/**
* The last run is updated every time a task is finished.
*
* @implSpec Synchronize in the field declaration order before modification
*/
private final Map<Identifier, Instant> lastRun;

/**
* Scheduled futures are returned from {@link #taskScheduler}.
* Futures are completed by execution of tasks created in {@link #createRunnableToSchedule}.
* Records about them are used for their cancellation in case of debouncing.
* Scheduled futures are returned from {@link #taskScheduler}. Futures are completed by execution of tasks created
* in {@link #createRunnableToSchedule}. Records about them are used for their cancellation in case of debouncing.
*
* @implSpec Synchronize in the field declaration order before modification
*/
private final NavigableMap<Identifier, Future<Object>> scheduledFutures;

/**
* Thread safe set holding identifiers of threads that are
* currently executing a throttled task.
* Thread safe set holding identifiers of threads that are currently executing a throttled task.
*/
private final Set<Long> throttledThreads = ConcurrentHashMap.newKeySet();

Expand All @@ -113,6 +112,7 @@ public class ThrottleAspect extends LongRunningTaskScheduler {

/**
* Used for acquiring {@link #lastRun} timestamps.
*
* @implNote for testing purposes
*/
private final Clock clock;
Expand All @@ -123,8 +123,8 @@ public class ThrottleAspect extends LongRunningTaskScheduler {
private final SynchronousTransactionExecutor transactionExecutor;

/**
* A timestamp of the last time maps were cleaned.
* The reference might be null.
* A timestamp of the last time maps were cleaned. The reference might be null.
*
* @see #clearOldFutures()
*/
private final AtomicReference<Instant> lastClear;
Expand Down Expand Up @@ -185,7 +185,8 @@ private static StandardEvaluationContext makeDefaultContext() {
/**
* @return future or null
* @throws TermItException when the target method throws
* @throws IllegalCallerException when the annotated method returns another type than {@code void}, {@link Void} or {@link Future}
* @throws IllegalCallerException when the annotated method returns another type than {@code void}, {@link Void} or
* {@link Future}
* @implNote Around advice configured in {@code spring-aop.xml}
*/
public @Nullable Object throttleMethodCall(@NonNull ProceedingJoinPoint joinPoint,
Expand Down Expand Up @@ -265,8 +266,8 @@ private static StandardEvaluationContext makeDefaultContext() {
if (oldScheduledFuture == null || oldThrottledFuture != future || oldScheduledFuture.isDone()) {
boolean oldFutureIsDone = oldScheduledFuture == null || oldScheduledFuture.isDone();
if (oldThrottledFuture != future) {
oldThrottledFuture.then(ignored ->
schedule(identifier, pair.getFirst(), throttleExpired && oldFutureIsDone)
oldThrottledFuture.then(ignored -> schedule(identifier, pair.getFirst(),
throttleExpired && oldFutureIsDone)
);
} else {
schedule(identifier, pair.getFirst(), throttleExpired && oldFutureIsDone);
Expand Down Expand Up @@ -352,11 +353,13 @@ private Pair<Runnable, ThrottledFuture<Object>> getFutureTask(@NonNull Proceedin
}
}, List.of());
} else {
throw new ThrottleAspectException("Invalid return type for " + joinPoint.getSignature() + " annotated with @Debounce, only Future or void allowed!");
throw new ThrottleAspectException(
"Invalid return type for " + joinPoint.getSignature() + " annotated with @Debounce, only Future or void allowed!");
}

final boolean withTransaction = methodSignature.getMethod() != null && methodSignature.getMethod()
.isAnnotationPresent(Transactional.class);
.isAnnotationPresent(
Transactional.class);

// create a task which will be scheduled with executor
final Runnable toSchedule = createRunnableToSchedule(throttledFuture, identifier, withTransaction);
Expand Down Expand Up @@ -391,14 +394,15 @@ private Runnable createRunnableToSchedule(ThrottledFuture<?> throttledFuture, Id
final Long threadId = Thread.currentThread().getId();
throttledThreads.add(threadId);

LOG.trace("Running throttled task [{} left] [{} running] '{}'", countRemaining() - 1, countRunning(), identifier);
LOG.trace("Running throttled task [{} left] [{} running] '{}'", countRemaining() - 1, countRunning(),
identifier);

// restore the security context
SecurityContextHolder.setContext(securityContext.get());
try {
// fulfill the future
if (withTransaction) {
transactionExecutor.execute(()->throttledFuture.run(this::notifyTaskChanged));
transactionExecutor.execute(() -> throttledFuture.run(this::notifyTaskChanged));
} else {
throttledFuture.run(this::notifyTaskChanged);
}
Expand All @@ -413,7 +417,8 @@ private Runnable createRunnableToSchedule(ThrottledFuture<?> throttledFuture, Id
notifyTaskChanged(throttledFuture); // task done
// clear the security context
SecurityContextHolder.clearContext();
LOG.trace("Finished throttled task [{} left] [{} running] '{}'", countRemaining(), countRunning() - 1, identifier);
LOG.trace("Finished throttled task [{} left] [{} running] '{}'", countRemaining(), countRunning() - 1,
identifier);

clearOldFutures();

Expand All @@ -425,13 +430,16 @@ private Runnable createRunnableToSchedule(ThrottledFuture<?> throttledFuture, Id

/**
* Discards futures from {@link #throttledFutures}, {@link #lastRun} and {@link #scheduledFutures} maps.
* <p>Every completed future for which a {@link Configuration#throttleDiscardThreshold throttleDiscardThreshold} expired is discarded.</p>
* <p>
* Every completed future for which a {@link Configuration#getThrottleDiscardThreshold()} expired is discarded.
*
* @see #isThresholdExpired(Identifier)
*/
private void clearOldFutures() {
// if the last clear was performed less than a threshold ago, skip it for now
Instant last = lastClear.get();
if (last.isAfter(Instant.now(clock).minus(configuration.getThrottleThreshold()).minus(configuration.getThrottleDiscardThreshold()))) {
if (last.isAfter(Instant.now(clock).minus(configuration.getThrottleThreshold())
.minus(configuration.getThrottleDiscardThreshold()))) {
return;
}
if (!lastClear.compareAndSet(last, Instant.now(clock))) {
Expand All @@ -444,7 +452,8 @@ private void clearOldFutures() {
.stream())
.flatMap(s -> s).distinct().toList() // ensures safe modification of maps
.forEach(identifier -> {
if (isThresholdExpiredByMoreThan(identifier, configuration.getThrottleDiscardThreshold())) {
if (isThresholdExpiredByMoreThan(identifier,
configuration.getThrottleDiscardThreshold())) {
Optional.ofNullable(throttledFutures.get(identifier)).ifPresent(throttled -> {
if (throttled.isDone()) {
throttledFutures.remove(identifier);
Expand All @@ -465,20 +474,22 @@ private void clearOldFutures() {

/**
* @param identifier of the task
* @param duration to add to the throttle threshold
* @return Whether the last time when a task with specified {@code identifier} run
* is older than ({@link Configuration#throttleThreshold throttleThreshold} + {@code duration})
* @param duration to add to the throttle threshold
* @return Whether the last time when a task with specified {@code identifier} run is older than
* ({@link Configuration#getThrottleThreshold()} + {@code duration})
*/
private boolean isThresholdExpiredByMoreThan(Identifier identifier, Duration duration) {
return lastRun.getOrDefault(identifier, Instant.MAX).isBefore(Instant.now(clock).minus(configuration.getThrottleThreshold()).minus(duration));
return lastRun.getOrDefault(identifier, Instant.MAX)
.isBefore(Instant.now(clock).minus(configuration.getThrottleThreshold()).minus(duration));
}

/**
* @return Whether the time when the identifier last run is older than the threshold,
* true when the task had never run
* @return Whether the time when the identifier last run is older than the threshold, true when the task had never
* run
*/
private boolean isThresholdExpired(Identifier identifier) {
return lastRun.getOrDefault(identifier, Instant.EPOCH).isBefore(Instant.now(clock).minus(configuration.getThrottleThreshold()));
return lastRun.getOrDefault(identifier, Instant.EPOCH)
.isBefore(Instant.now(clock).minus(configuration.getThrottleThreshold()));
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -544,7 +555,8 @@ private Identifier makeIdentifier(JoinPoint joinPoint, Throttle throttleAnnotati
if (Void.TYPE.equals(returnType) || Void.class.equals(returnType)) {
return null;
}
throw new ThrottleAspectException("Invalid return type for " + signature + " annotated with @Debounce, only Future or void allowed!");
throw new ThrottleAspectException(
"Invalid return type for " + signature + " annotated with @Debounce, only Future or void allowed!");
}


Expand Down Expand Up @@ -573,7 +585,8 @@ private Identifier makeIdentifier(JoinPoint joinPoint, Throttle throttleAnnotati
Objects.requireNonNull(identifierList);
return identifierList.stream().map(Object::toString).collect(Collectors.joining("-"));
} catch (EvaluationException | ClassCastException | NullPointerException e) {
throw new ThrottleAspectException("The expression: '" + expression + "' has not been resolved to a Collection<Object> or String", e);
throw new ThrottleAspectException(
"The expression: '" + expression + "' has not been resolved to a Collection<Object> or String", e);
}
}

Expand Down

0 comments on commit 270dc1b

Please sign in to comment.