Sharing a static object between a servlet and a webservice - java

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.

Related

More than one user in the same Controller Spring MVC

I'm starting to develop for Web and I'm using Spring MVC as my Server Framework. Now I'm wondering about creating variables in Controller class. I had to do it to manage some data in server, but now I'm concerned about the following case: If I have more than one user sending information to the same page, at the same time, would one user interfere on another user variable?
Here's some code example:
#Controller
public Class myController {
int number;
#RequestMapping("/userInformation")
public String getInformation(int info) {
number = info;
}
public void doSomethingWithIt() {
number = number + 1;
}
}
In this case, If I have more than one user sending data to /userInformation at the same time, would Spring MVC create one Controller for each user? This way I wouldn't have problem, I guess. But if not, I have to rethink this implementation, don't I?
You are right. Controllers are singletons and must be stateless. Server side state belongs in session or in a data store. You can also use a request scoped object (look at bean scopes in spring).
The Spring container will create one instance of your Controller. So all users will share that instance.
If you have data that is private to a user, you have several options:
store it in the HTTP session (not recommended if it's a lot of data, as your memory usage might explode)
store it in a database and retrieve it upon each request, based on some property identifying the user
store it in a memory cache and retrieve it upon each request, based on some property identifying the user
Option 3 is the most simple one of them, you can even implement it as a Map<User, UserData> instance variable on your Controller if you like. It's not the cleanest, most beautiful or most secure option, just the most simple.
You should not use any instance variables in the Spring Controller that represent state of the controller class. It should not have state since its single instance. Instead you could have references to the injected managed beans.

how to retain an object in java servlets as long as server works?

I want to create an object in java servlet and I need to persist the object into server session not user session I know how to do it in asp.net but in java servlet I am clueless.
Set it in the application scope.
From a servlet,
public void doPost(...) {
getServletContext().setAttribute("myPersistentObject", someObject);
}
From a JSP,
<%
application.setAttribute("myPersistentObject", someObject);
%>
Or better still, use JSTL:
<c:set value="${someObject}" scope="application" />
A servlet is a singleton. You can assign an instance variable of your servlet. Just make sure to properly synchronize the access to this variable.
You may also use the "application" scope, i.e. set an attribute in the ServletContext. The same synchronization warning applies:
request.getServletContext().setAttribute("foo", foo);
This way, the same object will be available from all the servlets, and from the JSPs using
${applicationScope.foo}
You need to provide more information for more precise answer.
In simple term, set the object as a static member of the servlet.
you can set object to ServletContext.
getServletContext().setAttribute("myObject1", object1);
will solve the purpose,you may elaborate your problem to get better answer.

How do I inject a dependency into a Jersey resource?

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.

Control of when do servlets die

I have some configuration stored in the servlet context, sharing among servlets. The current approach is to load the config into a single copy of static hashmap shared by the servlets when the init() method of any servlet is called. But the problem is the servlets just won't die, so the configuration just won't reset even if I changed the configuration in the servlet context. Because the servlet never call init() again, they will not reload the configuration into the hashmap.
I am using websphere 7, is there any place I can configure when does a servlet die, and a new servlet is born?
I think it is too clumsy to reload the configuration from the servlet context when there is a new request.
Edit:
I have a scheduler which will create a new thread to check for a specific data file, if the data file was new, it will create a hashmap(with content of the data file) as an attribute in the servlet context.
Now the servlets will check for the servlet context for the hashmap and copy it to a static hashmap for shared use among servlets when they are just created and call init(). But the problem is that the servlet won't die during the execution, it just make the scheduled action not working.
I am using websphere 7, is there any
place I can configure when does a
servlet die, and a new servlet is
born?
No.
Edit: I have a scheduler which will
create a new thread to check for a
specific data file, if the data file
was new, it will create a hashmap(with
content of the data file) as an
attribute in the servlet context.
Now the servlets will check for the
servlet context for the hashmap and
copy it to a static hashmap for shared
use among servlets when they are just
created and call init(). But the
problem is that the servlet won't die
during the execution, it just make the
scheduled action not working.
Refactor the settings into a separate data object (rather than a HashMap or servlet instance fields) to be shared by servlet instances. Change the scheduler/alarm to update the shared data object directly.
Why not store this data in JNDI, where the servlets can get it whenever they need it? That way, you have complete control of the data; the servlet lifecycle would no longer matter.

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.

Categories