Is Spring Framework HttpComponentsClientHttpRequestFactory thread safe? - java

Could I have multiple threads use the same static instance of HttpComponentsClientHttpRequestFactory to safely create their respective ClientHttpRequest?
I am not able to find any manual that would tell me the answer.
I am presuming it is thread-safe simply because the all createRequest methods actually perform a new instantiation of a request object. For example,
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest);
return new HttpComponentsClientHttpRequest(getHttpClient(), httpRequest, createHttpContext(httpMethod, uri));
}
But then it calls a few other methods which may not be thread-safe.
In fact, if you do know the answer, where is the manual that would tell me the thread safety of anything in Spring?

Generally, any class within Spring infrastructure ending in Factory is thread-safe once it's initialized (i.e., once the constructor is called and the bean is initialized with its property values). Technically it's not thread-safe between constructor call and property injection, but all of the Spring ApplicationContext implementations I know of block requests for beans until context initialization is complete.
Bottom line is: don't create Factory objects outside of Spring manually and you should be fine.

Related

How #ControlAdvice captures exceptions?

I'm on learning phase of Spring boot
I've code where its written like below to handle exception in whole application. Not sure how its working, but I have NoDataFoundException class in code and its being used at place where no data found issues are happening.
#ControlAdvice
class ControllerAdvisor {
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(NoDataFoundException.class)
#ResponseBody
public ResponseEntity<Object> handleNodataFoundException(
NoDataFoundException ex, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", "No cities found");
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
}
Want to know, how and when handleNodataFoundException method automatically gets called when NoDataFoundException instance gets created ?
Does spring calls this method handleNodataFoundException on the basis of #ExceptionHandler(NoDataFoundException.class) which is bind to method itself and moreover irrespective of name of the method ?
how spring looks for parameters required for above method ? what if it has more parameters in it ?
This is done by proxying (Proxy.class).
Proxying is a mechanism in which a kind of pseudo class is created dynamically and mimics your own class (same methods) and is used to intercept all the method calls. This way it can act before and after the method calls as it please, and in the middle call the real method that you developed.
When you create a #Service in Spring, or a #Stateless in EJB, you never actually create the instances, you delegate the instance creation on the framework (Spring or EJB). Those frameworks proxy your classes and intercept every call.
In your case, and putting it simple, the proxy has a catch around the real call to your method, that catch captures exceptions, and acts upon the framework configuration built based on all the annotations that you created (#ControlAdvice, #ExceptionHandler and so on). And so it can call the handleNodataFoundException(...) in the cases that you defined with annotations.
Update visualization via stacktrace
For instance, if you have two Spring #Component (or #Service, #Repository or whatever), and one calls the other one in a plain call, and you get an exception, in the stacktrace you see plenty of method calls (involving all kind of different classes) between your two component classes, all those are proxies and framework classes that take care of proxying, invoking, configuration and all the magic that the framework does. And everything is triggered by the proxy of your second component just before calling the real code that you developed, because the first component, at execution time, doesn't really call an instance of your class, but an instance of the proxy of your class that the framework created.
If you run a plain main, with two classes calling one to the other, instantiated by you with new, you will only see 3 lines in the stacktrace, because there the instances are plain instances created by you.

Using CDI with AsyncResponse and ExecutorService

Before adding CDI into our application I had created a resource that used the #Suspended AsyncResponse object to implement long polling for a chat client. What I did was create a new newSingleThreadExecutor() and submit a Runnable to it that used .wait(30000) on a message list until notification that a new message was sent. Inside that task I used the HttpServletRequest which was obtained using #Context and everything worked perfectly.
However once we added CDI to our application and even without making the resource class a bean (scanning only annotated beans and we didn't give it any scope annotation) I got a runtime exception that the request object INSIDE the Runnable task couldn't be accessed because of an illegal state exception:
Method threw 'java.lang.IllegalStateException' exception. Cannot evaluate com.sun.proxy.$Proxy74.toString()
I'm not really sure why this happens but I know it is CDI related since it refers to a proxy object. One guess is that the resource class itself has become CDI scoped and that scope can't be accessed from a different thread? I read somewhere that manually started threads are not managed and thus can't have access to any scope related objects. However how did this use to work until CDI was implemented?
Right now I THINK I've solved the issue (that is releasing the thread servicing request I/O and having a worker take over the waiting until notified) using jersey's #ManagedAsync annotation which supposedly has the whole method be run in an internal jersey executor service. Is this correct? Also in that case, is there any need of the AsyncResponse object?
EDIT: I have NOT solved the issue. #ManagedAsync worked when the resource class was not defined as a CDI bean. After making it #RequestScoped, whenever I try to call the method I get the following exception
org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
I think this is because the request can end before the async thread has finished which means all scope objects (like HttpServletRequest) will be destroyed and thus we won't have access to them. Is there a way to used #ManagedAsync in a #RequestScoped bean and make use of #Context HttpServletRequest??
TL;DR:
How can I have access to a context resource inside a manually started thread?
Why did I have access to the request object before CDI was implemented?
Is it possible to use #ManagedAsync in a #RequestScoped cdi bean?
Old method:
#GET
#Path("method")
public void method(#Context HttpServletRequest request, #Suspended AsyncResponse ar) {
//request object was accessible here
Executors.newSingleTHreadExecutor().submit(() -> {
//request object was also accessible here but lost access after implementing CDI.
Object o = foo.bar(request);
ar.resume(Response.ok(o).build());
});
}
Current non-working method:
#GET
#Path("method")
#ManagedAsync
public void method(#Context HttpServletRequest request, #Suspended AsyncResponse ar) {
Object o = foo.bar(request);
ar.resume(Response.ok(o).build()); //Is there any point to this?
}
To answer your question - no. You cannot use async and request scoped objects. Async support is lacking in CDI - see also https://issues.jboss.org/browse/CDI-452

JavaEE Web JAX-RS: can i use instance variables inside it's class?

I'm looking for thread-safe Servlet alternative and I've found JAX-RS technology.
So can i use instance variables inside it's class like this (is it thread safe):
#Path("helloworld")
public class HelloWorldResource {
private String msg;
#GET
public void doSmth() {
this.msg = "test";
}
}
?
Resource scope will default to #RequestScope so a new instance of your resource will be created per request.
From Chapter 3. JAX-RS Application, Resources and Sub-Resources
#RequestScoped
Default lifecycle (applied when no annotation is present). In this scope the resource instance is created for each new request and used for processing of this request. If the resource is used more than one time in the request processing, always the same instance will be used. This can happen when a resource is a sub resource is returned more times during the matching. In this situation only on instance will server the requests.
So as long as msg is not static it should be created per request.
This also means that after the request is handled you are going to lose any state contained in the resource, what use case are you trying to solve here?

JAX-RS (Jersey) ExceptionMapper - #Context injection into static/singleton class - it works, but why?

I have a single-instance class, implementing ExceptionMapper. It's not a static class, but it's a class for which I know only single instance is created (I checked - constructor is called only once).
My class uses #Context HttpServletRequest, and I can clearly observe that when my ExceptionMapper.toResponse() method is called, the #Context 'request' parameter has a value which is relevant for a request where the exception is thrown.
The doc says this is indeed by-design supported feature and that it's done by using "proxies".
I wonder how exactly this is implemented - how a single instance can have different member variable values simultaneously?
Thank you,
AG
P.S.: here's the test code:
#Provider
public class MyExceptionMapper implements ExceptionMapper<Exception> {
public MyExceptionMapper() {
System.out.println("CTOR!!");
}
#Context HttpServletRequest req;
public static boolean done = false;
public Response toResponse(Exception ex) {
if (!done) {
done = true;
Thread.sleep(10000);
}
System.out.println(req.getRequestURI());
return null;
}
}
My REST handler method throws exception, so when I execute the following 2 requests "in parallel" (the sleep above makes sure first one is not finished when second one arrives and IMHO should modify the one-and-only 'req' field):
- http://localhost/app/one
- http://localhost/app/two
my program prints:
CTOR!
http://localhost/app/one
http://localhost/app/two
The simplest method of achieving the effect you observe is for the injected HttpServletRequest object to actually be a proxy object, a thread-aware delegate for the real HttpServletRequest. When you call methods on the delegate, all they do is look up the correct real object (e.g., via a thread local variable) and pass the call onto that. This strategy is relatively simple to get right, and as it is an interface we definitely don't have to worry about field accesses (which are quite a bit trickier to proxy for).
There's a few different ways to construct such a proxy object. In particular, it could be done by directly implementing the HttpServletRequest interface, or it could be done more generically via the Java general dynamic proxy mechanism (which can construct a proxy for any interface). There are other more elaborate possibilities such as runtime code generation, but they're unnecessary here. OTOH, I wouldn't be at all surprised if HttpServletRequest was directly implemented; it's a somewhat important class for a JAX-RS implementation…

Using EJBContext getContextData - is this safe?

I am planning to use EJBContext to pass some properties around from the application tier (specifically, a message-driven bean) to a persistence lifecycle callback that cannot directly be injected or passed parameters (session listener in EclipseLink, entity lifecycle callback, etc.), and that callback is getting the EJBContext via JNDI.
This appears to work but are there any hidden gotchas, like thread safety or object lifespan that I'm missing? (Assume the property value being passed is immutable like String or Long.)
Sample bean code
#MessageDriven
public class MDB implements MessageListener {
private #Resource MessageDrivenContext context;
public void onMessage(Message m) {
context.getContextData().put("property", "value");
}
}
Then the callback that consumes the EJBContext
public void callback() {
InitialContext ic = new InitialContext();
EJBContext context = (EJBContext) ic.lookup("java:comp/EJBContext");
String value = (String) context.getContextData().get("property");
}
What I'm wondering is, can I be sure that the contextData map contents are only visible to the current invocation/thread? In other words, if two threads are running the callback method concurrently, and both look up an EJBContext from JNDI, they're actually getting different contextData map contents?
And, how does that actually work - is the EJBContext returned from the JNDI lookup really a wrapper object around a ThreadLocal-like structure ultimately?
I think in general the contract of the method is to enable the communication between interceptors + webservice contexts and beans. So the context should be available to all code, as long as no new invocation context is created. As such it should be absolutely thread-safe.
Section 12.6 of the EJB 3.1 spec says the following:
The InvocationContext object provides metadata that enables
interceptor methods to control the behavior of the invocation chain.
The contextual data is not sharable across separate business method
invocations or lifecycle callback events. If interceptors are invoked
as a result of the invocation on a web service endpoint, the map
returned by getContextData will be the JAX-WS MessageContext
Furthermore, the getContextData method is described in 4.3.3:
The getContextData method enables a business method, lifecycle callback method, or timeout method to retrieve any interceptor/webservices context associated with its invocation.
In terms of actual implementation, JBoss AS does the following:
public Map<String, Object> getContextData() {
return CurrentInvocationContext.get().getContextData();
}
Where the CurrentInvocationContext uses a stack based on a thread-local linked list to pop and push the current invocation context.
See org.jboss.ejb3.context.CurrentInvocationContext. The invocation context just lazily creates a simple HashMap, as is done in org.jboss.ejb3.interceptor.InvocationContextImpl
Glassfish does something similar. It also gets an invocation, and does this from an invocation manager, which also uses a stack based on a thread-local array list to pop and push these invocation contexts again.
The JavaDoc for the GlassFish implementation is especially interesting here:
This TLS variable stores an ArrayList. The ArrayList contains
ComponentInvocation objects which represent the stack of invocations
on this thread. Accesses to the ArrayList dont need to be synchronized
because each thread has its own ArrayList.
Just as in JBoss AS, GlassFish too lazily creates a simple HashMap, in this case in com.sun.ejb.EjbInvocation. Interesting in the GlassFish case is that the webservice connection is easier to spot in the source.
I can't help you directly with your questions regarding EJBContext, since the getContextData method was added in JEE6 there is still not much documentation about it.
There is however another way to pass contextual data between EJBs, interceptors and lifecycle callbacks using the TransactionSynchronizationRegistry. The concept and sample code can be found in this blog post by Adam Bien.
javax.transaction.TransactionSynchronizationRegistry holds a Map-like structure and can be used to pass state inside a transaction. It works perfectly since the old J2EE 1.4 days and is thread-independent.
Because an Interceptor is executed in the same transaction as the ServiceFacade, the state can be even set in a #AroundInvoke method. The TransactionSynchronizationRegistry (TSR) can be directly injected into an Interceptor.
The example there uses #Resource injection to obtain the TransactionSynchronizationRegistry, but it can also be looked up from the InitialContext like this:
public static TransactionSynchronizationRegistry lookupTransactionSynchronizationRegistry() throws NamingException {
InitialContext ic = new InitialContext();
return (TransactionSynchronizationRegistry)ic.lookup("java:comp/TransactionSynchronizationRegistry");
}

Categories