Stop Spring #Controller at runtime - spring

I've found Can a spring boot #RestController be enabled/disabled using properties? which addresses not starting a #Controller at boot time, but I'm looking for a way to stop a #Controller at runtime.

I would actually used the #RefreshScope Bean and then when you want to stop the Rest Controller at runtime, you only need to change the property of said controller to false.
SO's link referencing to changing property at runtime.
Here are my snippets of working code:
#RefreshScope
#RestController
class MessageRestController(
#Value("\${message.get.enabled}") val getEnabled: Boolean,
#Value("\${message:Hello default}") val message: String
) {
#GetMapping("/message")
fun get(): String {
if (!getEnabled) {
throw NoHandlerFoundException("GET", "/message", null)
}
return message
}
}
And there are other alternatives of using Filter:
#Component
class EndpointsAvailabilityFilter #Autowired constructor(
private val env: Environment
): OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val requestURI = request.requestURI
val requestMethod = request.method
val property = "${requestURI.substring(1).replace("/", ".")}." +
"${requestMethod.toLowerCase()}.enabled"
val enabled = env.getProperty(property, "true")
if (!enabled.toBoolean()) {
throw NoHandlerFoundException(requestMethod, requestURI, ServletServerHttpRequest(request).headers)
}
filterChain.doFilter(request, response)
}
}
My Github explaining how to disable at runtime

Related

Vaadin: Disable HTTP PUT/DELETE requests

I'm running Vaadin on Spring-Boot.
I tried implementing WebMvcConfigurer & and HandlerInterceptor to disable PUT & DELETE requests, but it is not working. I can see WebMvcConfigurer is getting loaded, but the preHandle method in the custom HandlerInterceptor never gets called.
I noticed Vaadin is loading AtmosphereInterceptor, wondering if that is overriding my custom spring settings.
Any idea what can I do to disable PUT & DELETE on all paths (/**) by default in vaadin?
edit code:
#Component
class HTTPRequestInterceptor extends HandlerInterceptor {
override def preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean = {
if (HttpMethod.GET.matches(request.getMethod) || HttpMethod.POST.matches(request.getMethod)) {
true
} else {
response.sendError(HttpStatus.METHOD_NOT_ALLOWED.value())
false
}
}
}
#Configuration
class HTTPRequestInterceptorConfig (#Autowired interceptor: HTTPRequestInterceptor) extends WebMvcConfigurer {
private val log = LoggerFactory.getLogger(classOf[HTTPRequestInterceptorConfig])
override def addInterceptors(registry: InterceptorRegistry): Unit = {
log.info("adding interceptors")
registry.addInterceptor(interceptor).addPathPatterns("/**")
}
}
Note: I tried both with & without #Autowired parameter.

Properties in application.properties not getting loaded in Filter class

I am trying to read the value from application.properties in one of the util library Filter we write.
My code is as below.
public class AuthorizationFilter extends GenericFilterBean
{
#Value ("${application.identifier}")
private String appId;
...
}
However the value appId is not read from application.properties though it is defined.
The issue occurs only with Filter classes.
Any pointers on how to fix this?
Like #M.Deinum said , If you let spring-boot manage the life cycle of the filter bean, then you will be able use the #Value annotation :
#Component
#Order(1)
public class CustomFilter implements Filter {
#Value ("${application.identifier}")
private String appId;
#Override
public void doFilter
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
LOG.info(
"Starting for req : {}",
req.getRequestURI());
chain.doFilter(request, response);
LOG.info(
"Anything");
}
// other methods
}
Keep in mind that if you provide your filter this way , you won't have to register it manually and if you want it to work for a particular url by registering it manually remember to remove the #Component annotation so that spring-boot won't take it up automatically.
Let the spring manage your filter class. You can register in your filter class like below :
#Bean
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(this);
registration.addUrlPatterns("/*");
return registration;
}

How to define global static header on Spring Boot Feign Client

I have a spring boot app and want to create a Feign client which has a statically defined header value (for auth, but not basic auth). I found the #Headers annotation but it doesn't seem to work in the realm of Spring Boot. My suspicion is this has something to do with it using the SpringMvcContract.
Here's the code I want to work:
#FeignClient(name = "foo", url = "http://localhost:4444/feign")
#Headers({"myHeader:value"})
public interface LocalhostClient {
But it does not add the headers.
I made a clean spring boot app with my attempts and posted to github here: github example
The only way I was able to make it work was to define the RequestInterceptor as a global bean, but I don't want to do that because it would impact other clients.
You can also achieve this by adding header to individual methods as follows:
#RequestMapping(method = RequestMethod.GET, path = "/resource", headers = {"myHeader=value"})
Using #Headers with dynamic values in Feign client + Spring Cloud (Brixton RC2) discusses a solution for dynamic values using #RequestHeader.
You can set a specific configuration class on your feign interface and define a RequestInterceptor bean in there. For example:
#FeignClient(name = "foo", url = "http://localhost:4444/feign",
configuration = FeignConfiguration.class)
public interface LocalhostClient {
}
#Configuration
public class FeignConfiguration {
#Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
#Override
public void apply(RequestTemplate requestTemplate) {
// Do what you want to do
}
};
}
}
You could specify that through the application.yml file:
feign:
client:
config:
default:
defaultRequestHeaders:
Authorization:
- Basic 3ncond2dS3cr2t
otherHeader:
- value
Note that this will be applicable to all your Feign Clients if it happened that you're using more than one. If that's the case, you could add a section per client instead of adding this to the default section.
Try this
#Component
public class AuthFeignInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate template) {
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
final HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
template.header("Header_name","Value");
}
}
}

initParams are not working in WebFilter annotation

I created a filter using following annotations in a java web project created by spring-boot:
#Order(2)
#Component
#WebFilter(
filterName = "jwtFitler",
urlPatterns = "/*",
initParams = { #WebInitParam(name = "excludedPaths", value = "login, hello") }
)
However, the initParams are not working, excludedPaths and excludedUrls are always null. Could anyone help tell me why?
public class MyFilter implements Filter {
private String[] excludedUrls;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
String excludedPaths = filterConfig.getInitParameter("excludedPaths");
System.out.println("excludedPaths:" + excludedPaths);
if(!StringUtils.isEmpty(excludedPaths))
excludedUrls = excludedPaths.split(",");
System.out.println("excludedUrls:" + excludedUrls);
}
//......
}
Due to your use of #Component, your Filter is being found as a plain Spring component. As a result, the #WebFilter configuration has no effect.
If you want Spring Boot to scan for Servlet components (#WebFilter, #WebListener and #WebServlet) you need to use #ServletComponentScan. Typically, that annotation is added to your main application class alongside #SpringBootApplication. With that in place, you should remove #Component from your Filter.

Vertx instance variable is null in Spring context

I defined a Spring Boot App as a Verticle as follows:
#SpringBootApplication
public class SpringAppVerticle extends AbstractVerticle {
private Vertx myVertx;
#Override
public void start() {
SpringApplication.run(SpringAppVerticle.class);
System.out.println("SpringAppVerticle started!");
this.myVertx = vertx;
}
#RestController
#RequestMapping(value = "/api/hello")
public class RequestController {
#RequestMapping(method = RequestMethod.GET, produces = "application/json")
public void getEcho() {
JsonObject message = new JsonObject()
.put("text", "Hello world!");
myVertx.eventBus().send(EchoServiceVerticle.ADDRESS, message, reply -> {
JsonObject replyBody = (JsonObject) reply.result().body();
System.out.println(replyBody.encodePrettily());
});
}
}
}
I have a second non-Spring Verticle that is basically a echo service:
public class EchoServiceVerticle extends AbstractVerticle {
public static final String ADDRESS = "echo-service";
#Override
public void start() {
System.out.println("EchoServiceVerticle started!");
vertx.eventBus().consumer(EchoServiceVerticle.ADDRESS, message -> {
System.out.println("message received");
JsonObject messageBody = (JsonObject) message.body();
messageBody.put("passedThrough", "echo-service");
message.reply(messageBody);
});
}
}
The problem is that I get a nullpointer at line myVertx.eventbus().send in SpringAppVerticle class as the myVertx variable is null.
How do I properly instantiate a Vertx variable in a Spring context in order that I can exchange message between my both verticles?
My project can be found here: https://github.com/r-winkler/vertx-spring
The reason of the exception is the following:
SpringAppVerticle bean that is created during spring init is another object than starts the spring boot application. So you have two objects, one that has start() method invoked and another one that doesn't. Second one actually handles requests. So what you need is to register verticles as spring beans.
For samples of vertx/spring interoperability please refer to vertx examples repo.
P.S. I've created a pull request to your repo to make your example work.

Resources