diff --git a/celements-spring-mvc/pom.xml b/celements-spring-mvc/pom.xml
index 67b7410..19658f8 100644
--- a/celements-spring-mvc/pom.xml
+++ b/celements-spring-mvc/pom.xml
@@ -38,6 +38,14 @@
org.slf4j
slf4j-api
+
+ com.google.guava
+ guava
+
+
+ one.util
+ streamex
+
com.celements
diff --git a/celements-spring-mvc/src/main/java/com/celements/spring/mvc/HelloWorldController.java b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/HelloWorldController.java
index a87dd98..44dc33f 100644
--- a/celements-spring-mvc/src/main/java/com/celements/spring/mvc/HelloWorldController.java
+++ b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/HelloWorldController.java
@@ -1,40 +1,18 @@
package com.celements.spring.mvc;
-import javax.inject.Inject;
-
-import org.springframework.beans.factory.BeanFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
-import org.xwiki.context.Execution;
-import com.celements.execution.XWikiExecutionProp;
import com.celements.spring.security.AuthenticatedBaseController;
-import com.xpn.xwiki.XWikiContext;
@RestController
public class HelloWorldController extends AuthenticatedBaseController {
- private final BeanFactory beanFactory;
-
- @Inject
- public HelloWorldController(BeanFactory beanFactory) {
- this.beanFactory = beanFactory;
- }
-
- @GetMapping("/helloworld")
+ @GetMapping
@PreAuthorize("permitAll()")
public String helloWorld() {
return "Hello World!";
}
- @GetMapping("/hellocontext")
- public XWikiContext helloContext() {
- return beanFactory
- .getBean(Execution.class)
- .getContext()
- .get(XWikiExecutionProp.XWIKI_CONTEXT)
- .orElseThrow();
- }
-
}
diff --git a/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyConfig.java b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyConfig.java
new file mode 100644
index 0000000..07e48ce
--- /dev/null
+++ b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyConfig.java
@@ -0,0 +1,11 @@
+package com.celements.spring.mvc.limiter;
+
+import static com.google.common.base.Preconditions.*;
+
+public record EndpointConcurrencyConfig(int maxConcurrent, int waitMillis) {
+
+ public EndpointConcurrencyConfig {
+ checkArgument(maxConcurrent > 0, "Endpoint concurrency limit must be positive");
+ checkArgument(waitMillis >= 0, "Endpoint concurrency wait time must be non-negative");
+ }
+}
diff --git a/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyLimit.java b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyLimit.java
new file mode 100644
index 0000000..4343a58
--- /dev/null
+++ b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyLimit.java
@@ -0,0 +1,16 @@
+package com.celements.spring.mvc.limiter;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Documented
+@Retention(RUNTIME)
+@Target({ TYPE, METHOD })
+public @interface EndpointConcurrencyLimit {
+
+ String value();
+}
diff --git a/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyLimiter.java b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyLimiter.java
new file mode 100644
index 0000000..166e1c7
--- /dev/null
+++ b/celements-spring-mvc/src/main/java/com/celements/spring/mvc/limiter/EndpointConcurrencyLimiter.java
@@ -0,0 +1,84 @@
+package com.celements.spring.mvc.limiter;
+
+import static com.google.common.base.Preconditions.*;
+import static java.util.concurrent.TimeUnit.*;
+import static org.springframework.core.annotation.AnnotatedElementUtils.*;
+import static org.springframework.http.HttpStatus.*;
+
+import java.io.IOException;
+import java.lang.reflect.AnnotatedElement;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.Semaphore;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+
+import com.celements.spring.mvc.CelMvcInterceptor;
+
+import one.util.streamex.EntryStream;
+
+@Component
+public class EndpointConcurrencyLimiter implements CelMvcInterceptor {
+
+ private final Map configs;
+ private final Map limiters;
+
+ @Inject
+ public EndpointConcurrencyLimiter(Optional