How do I inject a dependency into a Jersey resource? - java

I'm using Jersey to build a REST API, with Grizzly. I'm not using any dependency injection framework like Google Guice.
One of the resources needs to retrieve data from a Map in response to a GET request.
I can't figure out how I can inject this Map into the resource, since with Jersey I don't control how the resource is initialized.
I realize I could just declare the Map as static but that seems like a very ugly solution.

I eventually found the solution, I need to create a "Provider", as follows:
#Provider
public class DBPoolInjectableProvider extends SingletonTypeInjectableProvider<Context, BoneCPDataSource> {
public DBPoolInjectableProvider() throws SQLException {
super(BoneCPDataSource.class, APIMain.getDBPool());
}
}
As you can see, in this case I actually needed to get access to a database connection pool, but the same idea will work for any other type of object.
I just put this provider in a package that is scanned by Jersey and it picks it up and uses it whenever it sees a method like this in a Jersey resource:
public TestResponse testGet(#Context final BoneCPDataSource ds) throws SQLException {
...
}
(Personally I think that this kind of "action at a distance" is an anti-pattern, but I've got it working now so I'll shut up)

You can do the following:
Create a filter which has access to a map which you need.
Declare a thread local variable in the Filter
Before processing request, put a map into the variable
In your resource, when you need to have access to the map, access that local variable
After processing request, clean this map.
It's actually, almost the same as declaring a session per request with Hibernate/JPA.

Related

When to use #Singleton annotation of Jersey?

I am developing a RESTful Web Service and while reading the Jersey documentation I came across an annotation #Singleton
In my web service I am mostly returning data based on the unique keys provided as parameter.
An analogy would be return all the information of a Student when the Student_Id is passed.
So my question is when #Singleton would be suited in such kind of Web Services?
As per documentation for #RequestScoped
If the resource is used more than one time in the request processing, always the same instance will be used.
Then in that case we should not bother to use #Singleton right?
Also what could be the use cases where we have to make a new instance for every request?
I did have a look at this post but my question was not answered.
By default Jersey creates a new instance of the resource class for every request. So if you don't annotate the Jersey resource class, it implicitly uses #RequestScoped scope. It is stated in Jersey documentation:
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.
Most cases you use this default setting so you don't use #Singleton scope. You can also create a singleton Jersey resource class by using #Singleton annotation. Then you need to register the singleton class in the MyApplication class, e.g.,
#Path("/resource")
#Singleton
public class JerseySingletonClass {
//methods ...
}
public class MyApplication extends ResourceConfig {
/*Register JAX-RS application components.*/
public MyApplication () {
register(JerseySingletonClass.class);
}
}
Came along this question, because for the first time I had a use case for not using #Singleton annotation.
Singleton is a design pattern, you should use it if:
The object you are "singletonizing" keeps a state that must be shared and kept unique (example: a global counter)
Generally, I design REST API without keeping a state, everything is handled in the method (full closure): so generally all my resources are singletons (use case: better performance)
That said, today I found this use case for not using Singleton:
#Path("/someendpoint/{pathparam}/somethingelse/")
//#Singleton
public class MyResource {
#PathParam("pathparam")
private String pathparam;
}
Using this, I'm bounding the path param to my instance, so it must be RequestScoped.
Generally, I'd have put #PathParam annotation in every method, so #Singleton would have been right on the class.
I'm not sure about the performances however, creating and destroying an object isn't a free operation
In most cases default scope #RequestScoped should be sufficient for your needs.
#Singleton may hold state. I had the problem when my endpoint was annotated as #Singleton so it reused the same EntityManager during concurrent calls. After removing #Singleton, during concurrent calls, different EntityManager object instances are used. If endpoint calls are subsequent, it may be that previous/old EntityManager will be used. - Jersey, Guice and Hibernate - EntityManager thread safety
There is actually a use case specified in the Jersey 2 manual for using the SseBroadcaster when serving Server-Sent events, it is covered in this provided example
The BroadcasterResource resource class is annotated with #Singleton annotation which tells Jersey runtime that only a single instance of the resource class should be used to serve all the incoming requests to /broadcast path. This is needed as we want to keep an application-wide single reference to the private broadcaster field so that we can use the same instance for all requests. Clients that want to listen to SSE events first send a GET request to the BroadcasterResource, that is handled by the listenToBroadcast() resource method.
Using the #Singleton, The application will only contain one SseBroadcaster for all incoming requests, one such broadcaster is enough to serve multiple clients, so it only needs to be instantiated once!
JAX-RS SSE API defines SseBroadcaster which allows to broadcast individual events to multiple clients.

How do you configure a JAX-RS MessageBodyWriter on a per-request basis?

Essentially, I have a MessageBodyWriter that writes objects as JSON, and I'd like to be able to control some aspects of the output based on which resource method handled the request. However, the default lifecycle of #Provider classes is singleton (one per JVM), so I can't inject an instance of some configuration object. This leaves me with 2 obvious workarounds:
Use custom annotations: Each call to writeTo(...) includes the list of annotations on the method that was invoked, so I could check for the existence of some annotation. However, JAX-RS methods are already pretty laden with metaprogramming.
Use a ThreadLocal property map: Assuming one request per thread, but this approach breaks encapsulation a bit. The resource methods needs to be aware that there is some other class out there, looking for this map.
Is there a way to change the lifecycle of the Provider itself? I am using Jersey.
Not sure why you need a MessageBodyWriter Provider with per-request basis. If you just want to distinguish which methods are with JSON ouput and which are not, then jersey-json does already support.
And although the #Provider is singleton. You still can use per-request object within it like below.
#Provider
public class StViewProcessor implements ViewProcessor<ST> {
......
#Context
HttpServletRequest request;
public void writeTo(ST st, Viewable viewable, OutputStream out)
throws IOException {
System.out.println(request.getRequestURI());
...
}
}
And if you want to inject your instance per request, you can have a look at PerRequestTypeInjectableProvider. Here is a link about it.
The JAX-RS 1.1 spec requires that implementations support singleton providers and allows support for other lifecycles but doesn't suggest anything else along those lines. As far as I'm aware, pure Jersey doesn't support anything beyond singletons. With the jersey-spring contrib module, you get support for using Spring as Jersey's IoC container (where it gets its resource and provider instances from). I know Spring supports multiple lifecycles, including request, but I'm not sure if support for that is built into jersey-spring.

How to access the session from a Java class

I need to write a small Java class that will enable me to add to and read from the current user session.
Everything I see refers to Servlets but I'd ideally like to just use a plain old class.
Can anyone please help this Java Newbie?
Thanks
The general concept of a "Session" is really just a data storage for an interaction between a HTTP client and server. Session management is automatically handled by all HTTP Servlets. What framework?
If you're just wanting to store information for a console app to remember information between runs, then consider using Xml to save/load data from a file.
Use a component based MVC framework which abstracts all the ugly Servlet API details away so that you ends up with zero javax.servlet imports. Examples of such are JSF2 and Struts2.
In JSF2 for example, you'd just declare User class as a session scoped managed bean:
#ManagedBean
#SessionScoped
public class User {
// ...
}
Then in the "action" bean which you're using to processing the form submit, reference it as managed property:
#ManagedBean
#RequestScoped
public class SomeFormBean {
#ManagedProperty(value="#{user}")
private User user;
public void submit() {
SomeData someData = user.getSomeData();
// ...
}
}
That's it.
If you'd like to stick to raw Servlet API, then you've to live with the fact that you have to pass the raw HttpServletRequest/HttpServletResponse objects around. Best what you can do is to homegrow some abstraction around it (but then you end up like what JSF2/Struts2 are already doing, so why would you homegrow -unless for hobby/self-learning purposes :) ).
Yes, just pass the HttpRequest to your class from your servlet.
In your servlet do something like this,
cmd.execute(request);
In your class do something like this,
public class Command implements ICommand {
.
.
public void execute(HttpServletRequest request){
HttpSession sess = request.getSession(false);
}
.
.
.
}
In general, as mentioned in the other answers, session in many ways acts as a store. So to interact wth a session from another class which is outside of the Servlet/JSP framework the reference to the session in question needs to be procured. There are few ways it can be achieved:
1) Passing the session as part of a method parameter (already mentioned in other answers)
2) Binding the session to a thread local variable on to the current thread executing (refer ThreadLocal). This method has the advantage of not declaring specific parameters on the method signature of the class that needs to use the session. In addition, if the calling thread goes through a library and then again calls some specific class e.g. Servlet->YourClass0 -> Apache Some Library -> YourClass1, the session will also be available to YourClass1.
However, the thread local also needs to be cleared when the executing thread returns through the initial component (servlet let's say) otherwise there certainly could be memory leaks.
In addition, please refer to your specific framework for treatement of sessions, the above mechanism works fine in Tomcat.

Sharing a static object between a servlet and a webservice

I have a servlet which handles http get requests that I'd like to be able to share an object which is also used by a webservice im developing. They are both on the same tomcat server within the same web-app container. Im not sure best how to do it any ideas ?
You can share things across the webapp by storing them as attributes in the ServletContext (using setAttribute / getAttribute). You could create the object in an impelementation of ServletContextListener, store it in the ServletContext, and then retrieve it and use it from your web service and servlet.
I will expand on my comment here.
In the simplest case ServletContext.setAttribute/getAttribute would be fine. But some people rightly raised the questions about thread safety.
For this a better approach would be to store a shared POJO in a ServletContext during webapp initialization and get it wherever you need with ServletContext.getAttribute.
For this you need to implement ServletContextListener interface and declare it in your web.xml file.
<listener>
<listener-class>your.package.ServletContextListenerImpl</listener-class>
</listener>
This listener is called once when your webapp is loaded by the servlet container, and when it is about to be unloaded by the servlet container. In both cases it passes ServletContextEvent that has a handle to ServletContext. It is at that point that you want to set/removeAttribute that points to your shared object.
Because of this you may be certain that ServletContext.getAttribute will return a valid object when called from the Servlet.service or one of the do... methods.
As for attribute name, I would go with your Shared class classname. I would also add a static access method to your shared class to get it from the ServletContext, like this:
public class Shared
{
...
public static Shared fromServletContext ( final ServletContext context )
{
return (Shared) context.getAttribute( Shared.class.getName( ) );
}
}
The simplest option is create a Singleton - a class which allows only one instance in memory. Since you get it by calling a static method on the class itself it should be available to both the servlet and the WS
If my alternative understanding of the question is correct, the data which comes from request should be stored, and then retreived by the web-service. If this is supposed to run in a multi-user environment, you might consider using an in-memory database (HSQLDB) to temporarily store the data. Then you will be able to retrieve it with your web-service, based on some criteria I cannot foretell.
If this is application-specific data (accessible by all users (sessions)), then use ServletContext#set/getAttribute(). If this is user (session)-specific data, then use HttpSession#set/getAttribute().
Let the servlet class set the object in the desired scope (application or session) by a specific attribute key and let the webservice get the object from the desired scope by the same attribute key.
I think you rather need the HttpSession.
The singleton story makes no sense here.

tomcat session replication - not serialized exception

I am currently working on one messy web application. In this application, there is a class that holds all the data sources. And whenever the need to connect to a specific data source, the method in the instance of the class is called with a parameter to select the data source.And class is like follows
public class MyConnection implements Runnable,DbConnection, Serializable
{
private static final long serialVersionUID=2007L;
public static transient DataSource FirstDatasource;
public static transient DataSource SecondDatasource;
BaseDbConnection _bidc;
....
And on each page, this object is to get and set to the session(I don't know why like this). And it works fine with the current setup. (clustering, load balancing etc..)
But my work is to implement fail-over, and when I enable session replication(in memory - simple TCP), writing the session is failing and its throwing the following exception
org.apache.catalina.ha.session.DeltaManager requestCompleted
SEVERE: Unable to serialize delta request for sessionid [FE02AF01C76F41D042FE04692462D983.tomcat1]
java.io.NotSerializableException: org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapper
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1081)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1375)
.....
Since there are more than "I can count" no of pages, it's not easy to replace the code which sets the connection object in session from each and every page. And the complete app is based on this connection object(Datasources also play an important role).
Is there a way I can change this class so that it can be persisted in session?
If I understood correctly, I would say that replicating a DataSource is not correct, it can not work.
What need to be done is, after deserialing, to get a new (local) DataSource that corresponds to the need, and set it in the field. It is possible that this happens already in your code, look for a readResolve method.
If some parameters are needed to know which DataSource, they can be serialized themselves (because they are no DataSource, they could be just Strings for example).

Categories