Something missing using micronaut filter - filter

I am attempting to implement a filter in a micronaut microservice, using the example code documented in Section 6.18 of the documentation:
https://docs.micronaut.io/latest/guide/index.html#filters
I have a HelloWord service that is essentially the same as the service provided on the documentation, with a controller that goes to "/hello" (as documented). I am also using the same TraceService and trace filter that is provided in Section 6.18. I am compiling and running the server without problems.
Unfortunately, the filter is not being engaged when I test the microservice.
I am pretty sure that something is missing in my code, but as I said I am using the same code that is in the example:
TraceService Class
import io.micronaut.http.HttpRequest;
import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
import org.slf4j.*;
import javax.inject.Singleton;
#Singleton
public class TraceService {
private static final Logger LOG = LoggerFactory.getLogger(TraceService.class);
Flowable<Boolean> trace(HttpRequest<?> request) {
System.out.println("TRACE ENGAGED!");
return Flowable.fromCallable(() -> {
if (LOG.isDebugEnabled()) {
LOG.debug("Tracing request: " + request.getUri());
}
// trace logic here, potentially performing I/O
return true;
}).subscribeOn(Schedulers.io());
}
}
Trace Filter
import io.micronaut.http.*;
import io.micronaut.http.annotation.Filter;
import io.micronaut.http.filter.*;
import org.reactivestreams.Publisher;
#Filter("/hello/**")
public class TraceFilter implements HttpServerFilter {
private final TraceService traceService;
public TraceFilter(TraceService traceService) {
System.out.println("Filter created!");
this.traceService = traceService;
}
#Override
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
System.out.println("Filter engaged!");
return traceService.trace(request)
.switchMap(aBoolean -> chain.proceed(request))
.doOnNext(res -> res.getHeaders().add("X-Trace-Enabled", "true")
);
}
}
The Controller
import io.micronaut.http.annotation.*;
#Controller("/hello")
public class HelloController {
#Get("/")
public String index() {
return "Hello World";
}
}
Note that the controller uses code from Section 2.2 of the documentation:
https://docs.micronaut.io/latest/guide/index.html#creatingServer
I did a number of things to try and see what was happening with the filter, including putting little printouts in strategic parts of the Service and the filter. These printouts are not printing out, which tells me that the filter is not being created or used by Micronaut.
Clearly I am missing somethning. I suspect that there is something I need to do in order to get the system to engage the filter. Unfortunately the documentation just tells how to make the filter, not how to use it in the microservice. Furthermore, there don't appear to be any complete code examples that tell how to make the request system utilize the filter (maybe there is an annotation I need to add to the controller???).
Could someone tell me what I am missing? How do I get the filter to work? At the very least, could someone provide a complete example of how to create the filter and use it in an actual microservice?

Problem solved.
It actually helps a great deal if one puts the filter and service files in the right place. It was late when I made the files and I put them in the test area, not the development area. Once placed in the right place, the filter was properly injected into the microservice.
Sorry for the waste of space here, folks. Is there any way a poster can delete an embarrassing post?

Related

How to have dynamic base URL with Quarkus MicroProfile Rest Client?

Quarkus using Rest Client, explains how to use the MicroProfile REST Client. For Base URL application.properties can be used.
org.acme.restclient.CountriesService/mp-rest/url=https://restcountries.eu/rest #
With above approach, cant have dynamic base URL.
Able to achieve it by using RestClientBuilder as explained in MicroProfile Rest Client. Downside of this approach is not having auto-negotiation capability.
SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(getApplicationUri()).build(SimpleGetApi.class);
Is there other or better way to achieve this? Thanks.
While it is true, that the MP Rest CLient does not allow you to set the BaseUri dynamically when you use declarative/Injected clients, there are some (albeit hacky) ways how to achieve that.
One is to use standard ClientRequestFilter which can modify the URL:
#Provider
#Slf4j
public class Filter implements ClientRequestFilter {
#Inject RequestScopeHelper helper;
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
if (helper.getUrl() != null) {
URI newUri = URI.create(requestContext.getUri().toString().replace("https://originalhost.com", helper.getUrl()));
requestContext.setUri(newUri);
}
}
}
Where RequestScopeHelper is some help class (e.g. request scoped bean) through which you can pass the dynamic url, for example:
#Inject
RequestScopeHelper helper;
#Inject
#RestClient
TestIface myApiClient;
public void callSomeAPIWithDynamicBaseUri(String dynamic) {
helper.setUrl(dynamic);
myApiClient.someMethod();
}
Second is to use MP rest client SPI, namely the RestClientListener which allows you to modify the rest clients after they are built.
For this to work, you have to set the scope of your rest client to RequestScoped so that new instance is created for each request(if you use singleton for example, then the client is only created once and your listener will only be called once). This you can do via quarkus properties:
quarkus.rest-client."com.example.MyRestIface".scope=javax.enterprise.context.RequestScoped
public class MyListener implements RestClientListener {
#Override
public void onNewClient(Class<?> serviceInterface, RestClientBuilder builder) {
String newUri = //obtain dynamic URI from somewhere e.g. again request scope bean lookup, or maybe dynamic config source (create new in-memory ConfigSource, before you invoke your rest client set the corresponding rest client url property to your dynamic value, then inside this listener use ConfigProvider.getConfig().getProperty...)
builder.baseUri(URI.create(newUri));
}
}
Don't forget to register this listener as service provider(META-INF/services/org.eclipse.microprofile.rest.client.spi.RestClientListener)
Another option is to use custom CDI producer that would produce the Rest client instances for you; then you could control all client config yourself. You can use the RestClientBase from Quarkus rest client which is exactly what Quarkus uses under the hood during deployment phase to construct client instances. You will however have to duplicate all the logic related to registration of handlers, interceptors etc.
Do keep in mind, that any of these solutions will make the debugging and problem analysis more challenging - because you will now have multiple places, where the URI is controlled(MP config/quarkus properties, env vars, your custom impl...), so you need to be careful with your approach and maybe add some explicit log messages when you override the URI manually.
MicroProfile REST Client in Quarkus does allow you to use dynamic base URL with that simple "hack" :
Just put an empty String in #Path annotations for you API interface like that :
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("")
public interface SimpleGetApi {
#Path("")
#GET
String callWithDynmamicUrl(); //it can be String or any return type you want
}
After that you are ready to call your dynamic base URL :
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import java.net.URI;
public class Example {
public static void main(String[] args) {
URI anyDynamicUrl = URI.create("http://restcountries.eu/rest/some/dynamic/path");
SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(anyDynamicUrl)
.build(SimpleGetApi.class);
simpleGetApi.callWithDynmamicUrl();
}
}

Use CRNK without repository

We've standardized on using JSON:API for our REST endpoints, however; not all of our data revolves around repositories and it seems that CRNK requires repositories in order to work.
Is that correct?
Example
I wrote a very simple Spring Boot 2.1.9 example that has a single controller and included CRNK in it, but when I get into my controller I do not get the expected JSON:API output.
Please keep in mind, I am just starting to look at CRNK and this is just a simple "hello world" type of application that I am testing with
Here is my example
package com.example.crnkdemo;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/test/v1.0")
public class Controller {
#GetMapping(value = "/{country}", produces = "application/vnd.api+json")
public Country test1(#PathVariable String country, #RequestParam(name = "filter[region]", required = false) String filter) {
return new Country(country, filter);
}
}
Country is just a dummy class I created which is:
package com.example.crnkdemo;
import io.crnk.core.resource.annotations.JsonApiId;
import io.crnk.core.resource.annotations.JsonApiResource;
#JsonApiResource(type = "country")
#AllArgsConstructor
#Data
public class Country {
#JsonApiId
private String country;
private String region;
Results
But when I use the following URL http://localhost:8080/test/v1.0/US?filter[region]=northeast I get
{
"country": "US",
"region":"northeast"
}
I would have expected the JSON API type of result
{
"data": {
"type": "country",
"id": "US",
"attributes": {
"region": "northeast"
}
}
Thanks!
I ran into similar issue and the problem was that I got io.crnk:crnk-format-plain-json in my dependencies (simply copied from an example app) which changes the way how the responses look like (non-JSON-API). So first have a look into your maven/gradle configuration.
"not all of our data revolves around repositories"
you may also have a look at http://www.crnk.io/releases/stable/documentation/#_architecture where the architecture of resource-oriented framework like Crnk and JSON:API are discussed in more detail. In principle one can model everything as repository. Applications usually follow two kinds of patterns: CRUD ones and "actions". CRUD is simple: GET, POST, PATCH, DELETE objects. A repository is a perfect match for that. In contrast, people have a harder time when it comes to "actions". But this can be modelled as well as CRUD. For example, POSTing an AddressChange resource may trigger a server to start modifying the address(es) of some objects. This may happend immediately or take a longer time. Subsequent GET requests for the POSTed resources will reveal the current status of the action. And a DELETE request can cancel the request.
Crnk itself is not in need for Controllers as Spring MVC is. This kind of "lower-level plumbing" is taken care by Crnk itself because JSON:API specifies how a REST layer is supposed to look like. So there is no need to write custom code to specify urls patterns, parameters, etc. as in the MVC example above. Instead one can implement a repository:
public class TaskRepositoryImpl extends ResourceRepositoryBase<Task, Long> {
private ConcurrentHashMap<Long, Task> tasks = new Concurrent...
public TaskRepositoryImpl() {
super(Task.class);
}
#Override
public <S extends Task> S create(S entity) {
map.put(entity.getId(), entity);
return entity;
}
#Override
public ResourceList<Task> findAll(QuerySpec querySpec) {
return querySpec.apply(tasks.values());
}
...
}
There are also many built-in defult repository implementatons like for in-memory, JPA, security to cover the most frequent use cases.
with crnk, no need of writing controllers, manager classes. By default the controllers are defined.
Once we define the resources, we can access it by http://server_name:portno/crnk-path-prefix-property/defined_resourcename & the method type
Eg. In our case, resource is country, let's say server is running in localhost:8081 and crnk-path-prefix is /api/v1, then the url is http://localhost:8081/api/v1/country & set method type is GET, it will give the desired output. Remember to set content-type as application/vnd.api+json.
For POST, same url and set method type as POST, pass the data object
For PATCH, same url along with id attribute appended to the url and set method type as PATCH & pass the data object

Extending GitInfoContributor to add properties?

Before I discovered Spring Boot's Info Actuator had almost everything I wanted to publish, I made a few meta endpoints to ensure that I could access build and Git information that would help when trying to validate things like:
"Is the right version deployed?"
"Who built this?"
"When was it built?"
"Which git commit is this based on?"
After doing that, I did get around to discovering the Info actuator and that it answers almost all of those questions for me, but there are a few things from the Git information that I'd like to add -- mostly the commit message and the dirty flag.
I looked at the output if I turn on full git metadata with:
management.info.git.mode=full
But ... that adds a lot more information, most of which I don't care about, so it's more than I really want.
What I'd like to do is take the GitInfoContributor and extend/replace it, but I'm not totally sure how to do that. It's easy to add my own contributor, but if I add my own contributor and call builder.withDetails("git"), like this:
package ca.cpp.api.submitapi.config
import org.springframework.boot.actuate.info.Info
import org.springframework.boot.actuate.info.InfoContributor
import org.springframework.boot.info.GitProperties
import org.springframework.stereotype.Component
#Component
class CustomGitInfoContributor(private val properties: GitProperties): InfoContributor {
override fun contribute(builder: Info.Builder?) {
builder?.withDetail("git",mapOf("dirty" to properties.get("dirty"))
}
}
This replaces the whole set of git properties, and in the meantime, I think the core GitInfoContributor will still be there, still be providing information that I'm throwing away.
Is there a reasonable way to add only the elements I want, either with my own contributor that can merge its information with the info already under "git" or by somehow extending/replacing the existing GitInfoContributor?
Simplest way to add new element under "git" part is extending GitInfoContributor
kotlin:
#Component
class CustomGitInfoContributor #Autowired
constructor(properties: GitProperties) : GitInfoContributor(properties) {
override fun contribute(builder: Info.Builder) {
val map = generateContent()
map["dirty"] = properties.get("dirty")
builder.withDetail("git", map)
}
}
java:
#Component
public class CustomGitInfoContributor extends GitInfoContributor {
#Autowired
public CustomGitInfoContributor(GitProperties properties) {
super(properties);
}
#Override
public void contribute(Info.Builder builder) {
Map<String, Object> map = generateContent();
map.put("dirty", getProperties().get("dirty"));
builder.withDetail("git", map);
}
}
This code will add dirty part after default git info e.g. {"git":{"commit":{"time":"2018-11-03T15:22:51Z","id":"caa2ef0"},"branch":"master","dirty":"true"}}
In case you do not want to generate the default git info part simple remove generateContent() call.

Embedding Vaadin + Springboot application into a Vaadin UI using Emdedded UI add-on

I am currently working on microservices using springboot and Vaadin 8, and I want to use Embedded UI 2.0 add-on for Vaadin.
I first tried embedding a simple Springboot + Vaadin into a host Vaadin application as shown in the example.
Here's the result code for the host application :
import ...
import org.vaadin.embedded.VaadinUIComponent;
#Theme(ValoTheme.THEME_NAME)
public class HostUI extends UI {
#Override
protected void init(VaadinRequest vaadinRequest) {
/*My Spring boot application */
VaadinUIComponent ui1 = new VaadinUIComponent("http://localhost:8081/app2/");
ui1.setSizeFull();
/* A simple vaadin application*/
VaadinUIComponent ui2 = new VaadinUIComponent("http://localhost:9020");
HorizontalSplitPanel split = new HorizontalSplitPanel(ui1, ui2);
split.setSizeFull();
setContent(split);
}
But I keep having an issue with VAADIN/* resources loading :
{"timestamp":1501683162735,"status":404,"error":"Not Found","message":"No message available","path":"
/app2/widgetsets/ws84167e472e91ff0ea8255f8f1b189aa0/ws84167e472e91ff0ea8255f8f1b189aa0.nocache.js"}
where /app2/ is the path to my application.
I'm not sure how the path to the resources are resolved, but I know that the Vaadin directory is supposed to be /app2/VAADIN/* since the widgetsets and other vaadin compiled resources are working just fine and are available when I open the application directly from my browser.
Here are some additional information :
Vaadin version : 8.0.5
Embedded UI add-on version : 2.0
I used ValoTheme for all 3 applications (host and embedded)
vaadin.widgetset.mode is set to fetch mode
I made sure that CORS is enabled for the applications.
I searched quite a while to resolve this issue but couldn't find enough sources for this particular situation, and I'm also a beginner in both Spring and Vaadin, so I could definitely use some help.
Nice explanation by Morfic! Thanks. And yeah, there was a problem with the add-on. Fixed in 2.1. Please see more info at https://vaadin.com/forum#!/thread/16448312
TL;DR; version
This seems to be a bug in the add-on, and there's a similar issue open on their tracker, not sure whether it's you or someone else. But why do you need to use it in the first place? What are you trying to achieve that can not be done with a regular Vaadin application and you need to embed multiple UIs?
Detailed version
So I've done some digging and your observation is correct, /VAADIN/ is missing from the path. There may also be other failing requests which are handled by vaadinServlet in a spring boot app, such as heartbeat and uidl.
Stand alone app-request:
Embedded app-request:
With a little mode debugging, it seems that the add-on is indeed using an incorrect path:
Finally traced back to an incorrect regex replacement of ./VAADIN with http://localhost:9030/ instead of the correct one http://localhost:9030/VAADIN.
It seems to me like it's a bug in the add-on, but probably only the dev can confirm or explain why it's being done like this.
As a work around we can use a spring controller to redirect the requests to the correct URLs, but even this has it's limitation. It breaks at the first page refresh, because the v-uiId which is normally increased, remains 0.
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
#Controller
public class VaadinRedirectController {
private static final String INCOMPLETE_WIDGETSET_PATH = "/widgetsets/**";
private static final String INCOMPLETE_THEME_PATH = "/themes/**";
private static final String INCOMPLETE_UIDL_PATH = "/UIDL/**";
private static final String INCOMPLETE_HEARTBEAT_PATH = "/HEARTBEAT/**";
#RequestMapping(value = {INCOMPLETE_WIDGETSET_PATH, INCOMPLETE_THEME_PATH,})
public String redirectWidgetsetAndThemeRequests(HttpServletRequest request) {
return createRedirectPath(request, "VAADIN");
}
#RequestMapping(value = {INCOMPLETE_UIDL_PATH, INCOMPLETE_HEARTBEAT_PATH})
public String redirectUidlAndHeartbeatRequests(HttpServletRequest request) {
return createRedirectPath(request, "vaadinServlet");
}
private String createRedirectPath(HttpServletRequest request, String prefix) {
String path = "redirect:/" + prefix + getPath(request);
if (request.getQueryString() != null && !request.getQueryString().isEmpty()) {
path += "?" + request.getQueryString();
}
return path;
}
private Object getPath(HttpServletRequest request) {
return request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
}
}

What is the use case of skipping method execution in around advice?

I understood what #Around Advice does, and when we need to share Before and after state then we can use it, and we call also skip method execution. My question is why Spring given us this power to skip method execution and what is the use case of skipping method?
Side effects as NĂ¡ndor said are one thing. Maybe you even want to replace the return value altogether, possibly because there is a bug in a class you do not have the source code of or for other reasons:
Buggy Java class:
package de.scrum_master.app;
public class Earth {
public String getShape() {
return "disc";
}
}
Driver application:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
System.out.println("The Earth is a " + new Earth().getShape() + ".");
}
}
Console log:
The Earth is a disc.
Bugfix aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Earth;
public aspect BugfixAspect {
String around() : execution(* Earth.getShape()) {
return "sphere";
}
}
Console log with aspect applied:
The Earth is a sphere.
Method calls usually have side effects. Whenever you decide in your aspect that those side effects are undesirable for whatever reason, it's a valid use case to skip executing the original execution. This includes use cases for caching for example, when the side effects are not in terms of data, but execution time.

Resources