Best practices for using jersey client via guice injection - jersey

I'm using Jersey-2.19.x in my application to call rest APIs. Since jersey clients are expensive to create, I wanted to reuse the client for my API calls and therefore inject the client via guice injection.
Here is my guice code for injecting jersey client:
#Provides
#Singleton
Client getClient() {
return ClientBuilder.newClient();
}
And here is my class that uses this injection:
#Inject
public MyClass(Client client) {
this.client = client;
}
public callPost(String uri) {
// code to set web target and invoke
}
Now my question is, how can I close this injected client? What happens if jersey clients are never closed? And what are some best practices for using jersey client via dependency injection?

You need a shutdown hook.
Here is a good article that might be somewhat of an overkill for your situation: https://richardstartin.github.io/posts/lifecycle-management-with-guice-provision-listeners
If you want to keep things simpler, and you don't need to close anything but the Jersey client, you could try something like this:
public static void main(String args[]) {
Injector injector = Guice.createInjector(/* modules... */);
Client jerseyClient = injector.getInstance(Client.class);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override public void run() {
jerseyClient.close();
}
});
// proceed as normal
}

Related

How do I setup baggage fields in Spring Cloud Sleuth for a Command Line Runner?

I'm successfully using Spring Cloud Sleuth in a Spring Boot microservice and am having fields logged and sent over http headers appropriately.
I now need to integrate this same process for logging and header propagation in a Spring Boot command line runner application but it looks like no trace and span are automatically setup since it isn't in the middle of an Http request (as it is a command line app). I cannot see these fields in my logs (with the same %X format in log configuration).
I've looked at the docs and can't find any examples for this specific use case. Is this possible in a command line runner app?
In order to add baggage you need to have a span. Spring Cloud Sleuth and Spring Boot create a span for you when the controller is invoked. If you want to do the same using CLI application, you need to create span yourself.
You have two options.
Using API calls:
Span span = this.tracer.nextSpan().name("mySpan");
// do some work
span.end(); // best to put it in finally to make sure span is always ended
Or you can use annotations:
#NewSpan
public void doWork() {
}
If you use the annotation, please keep in mind the AOP proxies limitations. In particular self invocations (calls using this) would not work.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Override
public void run(String... args) {
doWork(); //this is the same as this.doWork();
}
#NewSpan
public void doWork() {
}
}
This is not going to work as doWork is not invoked through the AOP proxy. Make sure that you annotate a component managed by Spring and then use an injected instance.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Autowired
private MyService myService;
#Override
public void run(String... args) {
myService.doWork();
}
}
#Component
class MyService {
#NewSpan
public void doWork() {
}
}
In this case myService is not instance of MyService, but rather an instrumented proxy.

Instantiating server in Spring Framework 5 and Spring Boot 2

I am using Spring Boot 2 just to try some reactive programming with Spring 5. I created some standard MVC controller.
#RestController
#RequestMapping("/judge/rest")
public class BasicController {
private static final Logger LOGGER = LoggerFactory.getLogger(BasicController.class);
#GetMapping("/hello")
public Mono<String> handle() {
LOGGER.debug("Invoking hello controller");
return Mono.just("Hello WebFlux");
}
}
And standard router function.
#Configuration
public class WebConfig {
#Bean
public RouterFunction<?> helloRoute() {
return route(GET("/judge/router/hello"),
request -> ServerResponse.ok().body(fromPublisher(Mono.just("Hello Router WebFlux"), String.class)));
}
}
My main spring boot application looks like this
#SpringBootApplication
public class JudgeRuleEngineApplication {
public static void main(String[] args) {
SpringApplication.run(JudgeRuleEngineApplication.class, args);
}
}
But in documentation for spring 5 I ran into
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
ReactorHttpHandlerAdapter adapter =
new ReactorHttpHandlerAdapter(httpHandler);
HttpServer server = HttpServer.create("localhost", 8080);
server.startAndAwait(adapter);
It seems that server is intantiated manually.
My question is when should I instantiate the server like this? Because so far it seems with #SpringBootApplication and main it handles requests just fine.
As the document says
Now there is just one piece of the puzzle missing: running a router
function in an HTTP server. You can convert a router function into a
HttpHandler by using RouterFunctions.toHttpHandler(RouterFunction).
The HttpHandler allows you to run on a wide variety of reactive
runtimes: Reactor Netty, RxNetty, Servlet 3.1+, and Undertow.
Which means the above code which you have shown, uses Reactor Netty as the reactive runtime. If you wish to use any other runtimes which has reactive native adapter, you can do so. In such cases you would instantiate the server like this.
By default Spring boot default to Reactor Netty.

How to Create Spring WebSocket Application With HTML5 WebSocket API?

Recent Version of Spring WebSocket works with SockJS and StompJS libraries. But i don't like to use theme in my application. So how to create Spring WebSocket application with HTML5 WebSocket API and integrate our application with Spring Security?
I could not find any good example on how to configure spring websocket without sockjs but i found some helpful documentation in spring documentation site and i like to share that. Well, How to Create Spring WebSocket Application With HTML5 WebSocket API?
First: Create a Class that extends TextWebSocketHandler or BinaryWebSocketHandler and Annotate it with #Component annotation and Override its appropriate method.This Class works like handler methods in controllers.
#Component
public class SimpleWebSocketHandler extends TextWebSocketHandler {
#Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message) throws Exception {
// Sends back response to client.
session.sendMessage(new TextMessage("Connection is all right."));
}
}
Second: Create a Configuration Class that implements WebSocketConfigurer and Annotate it with #Configuration and #EnableWebSocket annoations and Override its appropriate method.This Class uses Handler Class that we created already.
#Configuration
#EnableWebSocket
public class WebSocketConfigurations implements WebSocketConfigurer {
#Autowired
private SimpleWebSocketHandler simpleWebSocketHandler;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// Regsiters a handler for related endpoint.
registry.addHandler(simpleWebSocketHandler, "/chat");
}
}
Third: Add all your WebSokcet Endpoints to your Spring Security Configuration.
httpSecurity.authorizeRequests()
.antMatchers("/chat").permitAll();
Fourth: We create a new javascript WebSocket objet with appropriate URL.
// Create WebSocket Object.
var ws = new WebSocket("ws://localhost:8080/chat");
// Runs when connecion is estabilished.
ws.onopen = function () {
// Sends request to server with string value.
ws.send("webSocket");
};
// Runs when response is ready.
// Use event to get response value.
ws.onmessage = function (event) {
};
Note: WebSocket URLs Format: ws://domain:port/endpoint

Cannot resolve symbol ExternalServiceResource while registering http client to jersey environment in Dropwizard Application

Iam implementing Dropwizard client in a Dropwizard REST Application.
I am following their User Manual.
While trying to register the client to jersey environment but cannot find the class ExternalServiceResource
#Override
public void run(ExampleConfiguration config,
Environment environment) {
final HttpClient httpClient = new HttpClientBuilder(environment).using(config.getHttpClientConfiguration())
.build();
environment.jersey().register(new ExternalServiceResource(httpClient));
}
I think that ExternalServiceResource was an example but it would look like:
#Path("/your/path")
public class ExternalServiceResource {
private final HttpClient client;
public ExternalServiceResource(HttpClient client) {
this.client = client;
}
#GET
public String doStuff() {
return /* use client to make some call */;
}
}
You can put whatever name you want. The only requirement to create a resource is the #Path annotation, that you must put at class level, and some methods #GET, #POST...

Problems injecting a BayeuxService into another class with annotations

I have a web app that is using Bayeux to handle Comet connections. I initialize a BayeuxServer and tie it into Spring annotations and it all works fine, listening on selected channels and responding.
I have a Jersey annotated class and an annotated Bayeux service as shown below. The idea is I wanted to be able to control resources via Rest from an individual web app, and then right after the resource is changed, do a server push via Comet to all other applicable clients to tell them to update their information.
Here is the problem: A Bayeux Service is created when the webapp is deployed, setting up proper channels to listen on and monitoring clients. There should only be one instance of this. When Jersey attempts to use the Bayeux service it creates a whole new service, when it should be using the original one. This new service doesn't have the BayeuxServer properly injected so I can't access client information through it.
It makes since that this should be doable, but I don't seem to understand how to inject these things properly via annotations. Can anyone point me in the right direction?
Jersey Annotated Class:
#Path("JsonTest")
public class JsonTest {
#Context
Request request;
#Context
UriInfo uriInfo;
#Context
ResourceContext resourceContext;
protected final Logger log = Logger.getLogger(getClass());
public JsonTest() {
}
#DELETE
#Path("{id}")
public void deleteJson(#PathParam("id") String id) {
JsonTestDao.instance.getModel().remove(id);
log.info("Deleted Json..." + id);
log.info("New json: " + JsonTestDao.instance.getModel().toString());
JsonTestService jsonTestService = resourceContext.getResource(JsonTestService.class);
jsonTestService.sendUpdate();
}
}
BayeuxService:
#Named
// Singleton here didn't seem to make a difference
#Service
public class JsonTestService {
protected final Logger log = Logger.getLogger(getClass());
#Inject
private BayeuxServer bayeux;
#Session
private ServerSession serverSession;
#PostConstruct
public void init() {
log.info("Initializing JsonTest Bayeux HelloService...");
log.info("Current sessions are: " + bayeux.getSessions().toString());
}
#Listener("/cometd/JsonTest")
public void jsonTestHandler(ServerSession remote, ServerMessage.Mutable message) {
}
public void sendUpdate() {
//bayeux.newMessage(); // Need a method that the Jersey class can call to notify changes
log.info("Bayeux server should be sending an update now...");
}
#PreDestroy
public void destroy() {
log.info("Destroying JsonTest Bayeux HelloService...");
}
}
See Jersey and spring integration - bean Injections are null at runtime.
Another question I asked. Both of these stem from the same problem involving properly setting the Jersey dependency and integrating it with spring.

Resources