I have a bunch of Servlets. I want all of them to instantiate a Logger, pretty much the exact same way.
Is there a proper (like a Main file) where I can bootsrap such code?
Currently what I do is created a subclass of the Servlet class, which does that in the init function and all the other Servltes inherit from it.
I don't know if it's a good idea what you are trying for the logger (i think you will lose some logger capacibilities), but well, if you want an unique instance of something in a servlet you should declare it and init it in the static way:
static final SomethingClear GLOBAL;
static{
// do tons of things to init
GLOBAL = ClassWithStaticFunc.gimmeGlobalLoaded();
}
An why is better this way? because there's another funny -or well, may be annoying :( - way to load a static (in the senses of uniqueness and that always will be an instance in memory) variable in a servlet:
Servlets dont have nothing like 'main'. They are unique instances which live in a servlet container, are instanciated by it, and its methods (doGet, doPost, doPut, doDelete) are executed by the servlet container on demand giving them request and response objects. So, in memory, there will be allways one and only one instance of each servlet, so any variable outside doGet, doPut, doDelete and doPost will be unique in memory. This was done this way in the beginings of the java-time in order to save memory...
And this is a funny way to merge sessions... :(
If you assing something to anything outside that methods in a servlet it will be assigned to all sessions of your application, and is not obvious and is not so easy to find...
So its better to mark them as static and final because they'll be always created (you have no access to objects construction) and there will be only one instance. It's not nice, but servlets are not nice...
I once did a unique servlet whose invoke my custom 'Servlets' using reflection (one object per petition, giving the name of my 'servlet' in the web.xml as initParam and setting the servlet-name always to the same servlet that was the instanciator of mines) to solve session merges and worked great.
Related
I have seen that you can call getservletcontext() directly also and also like this req.getsession().getservletcontext() .
What is the difference between the two and which one should I use ? Is there any scenario based on which I should use one and not the other?
And by the way I am using web module 2.5
What is the difference between the two
There is no difference between the two, they are one and the same.
The method getServletContext() that you can call directly is only when your code is in a class that extends HttpServlet. That is because HttpServlet base class has this method defined (actually in the GenericServlet class that HttpServlet extends).
The ServletContext returned by req.getSession().getServletContext()is same as the one returned above.HttpSessioncontains a reference to theServletContext` that this session belongs to.
which one should I use? Is there any scenario based on which I should use one and not the other?
As long as your code is in the servlet class, you can use anything as both can be called.
Let's say (hypothetically) you call a method in your custom class from your servlet and pass the session object to it to work on some data in the session. This custom class doesn't extend servlet. You need a reference to the ServletContext in this custom class. Since you have a reference to the session, you can get access to the ServletContext using the method session.getServletContext().
Hope this is clear.
The Session variables are only saved for one browser and the Context variables can be used by all browsers in one session.
So if the user only uses one browser (as it is in most cases) there is no difference between them, but if you like to work from different browsers in one session better use the Context.
I understand that this is normally not done, and I've found a number of instances of this question around the web with answers of the sort: "Your design is wrong if you need to do this." Let me explain my goal.
I have a web app that at one site somehow caused one servlet's init() method to be called repeatedly. I don't know how this happened and I cannot repeat it. However, from a binary heap dump (caused by an out-of-memory exception), it is very clear from objects on the heap that a specific servlet's init() method got called about 10,000 times, as that is the only place these objects are created and there were 10,000+ instances of an object that is supposed to have no more than one instance.
Since I cannot reproduce what happened at this one site, I instead want to forcefully invoke init() many times on this servlet, preferably via a JSP file, so I can test before and after a fix is applied. Testing the "after" case is easy in theory because I can change the code to (for example) stick this servlet into the context so I can get it and repeatedly call init() to prove that there is no leak of this object. But this does not help me test the "before" case with the existing code.
I cannot just "(new MyServlet()).init()" in a JSP. This fails as the servlet is created with a null context and fails to initialize. By Tomcat 5.5, it seems that ServletContext.getServlets() always returns an empty Enumeration and that ServletContext.getServlet(String) always returns null.
It seems the easiest way to test is if I can somehow programmatically (preferably from a JSP) get access to the servlet instance in question, or alternately, programmatically add new mappings to that same servlet class, which might create new instances. (?)
You've already figured out that what you are attempting is highly out of the ordinary and far from a best practice so I won't go into any detail on that subject. Having said that, if you want to invoke MyServlet.init() many times on an instance of MyServlet running within Tomcat, you could subclass MyServlet, override the doGet() or doPost() method, add a loop that simply calls this.init(); 1000 times and then call the parent classes doGet()/doPost(). Edit WEB-INF/web.xml to use your subclass in place of MyServlet. Then just hit the servlet with your web browser and see init() called 1000 times prior to serving the page normally. And you haven't modified the original MyServlet class at all, keeping your before test pure.
You can create a servlet instance like any other class object. Get hold of the servlet config by overriding the method init(ServletConfig config). And create the servlet class instance as many as u want, and call init(ServletConfig config) on all those instances created.
I'm in the situation where I need to create a cache to store certains values which need to be updated from the database. Since this cache needs to be singular, some sort of singleton implementation seems appropriate.
The problem is that this cache also needs access to the database via an EJB, which can't be injected since the cache exists outside of context (and yes, I'm looking forward to the #singleton annotation in EJB3.1).
The obvious solution is to pass the EJB into the cache as a parameter, but passing EJBs outside of context feels wrong, though I can't say why. Is it accepted practice?
Do note that you are normally not passing the EJB itself "outside of context". What you are typically passing around is a 'stub'. This stub can be passed around as any other normal object reference. Any calls on it will redirect back to an actual bean instance in the EJB container.
So if you have a cache in say the web module, have a backing bean injected with an EJB (or do a JNDI lookup) and pass that reference to a (static) cache, then I don't see a fundamental problem with that.
For all intends and purposes, the #Singleton annotation was indeed made for something like this. Hope you'll able to use it soon ;)
The main advantage of EJB is inside container. If you pass it outside you loose all the advantages which a container provide. Why don't you create a method in EJB that return the data you need. And the you can do, for example, JNDI lookup and call that method. In this way EJB will stay in the container and you will get your data.
I have a couple of global variables in a servlet. Individual servlet sessions read from and wrote to these variables. They are used to coordinate values posted to a database so it is important that the sessions remain in synch. My question is can I use synchronize key words with servlets to keep different servlet sessions from colliding with each other at these global variables?
Thank you,
I'd recommend not doing stuff like this in the servlet class itself. Have your servlet's doGet() etc. call into another object to do the real work. If this delegated class is a singleton then you have full control over initialization, state etc.
If you rely on how the app server loads the servlet class itself things can get brittle. Best to just let the server classload/share the servlet whenever it feels like and not depend on specific behavior.
I would like to read some parameters during servlet initializtion (in init() method), and store them among servlet context attributes (using getServletContext().setAttribute()). I would like to read these parameters later - during some request processing (using getServletContext().getAttribute()). So, the multiple threads could do this simultaneously. My question is if such an attempt is safe? Could I be sure that multi threaded calls to the getAttribute() don't mess up any internal state of the servlet context?
Please take into account that I'm not going to call the setAttribute() anywhere besides the initialization. So, only calls to the getAttribute() are going to be done from multiple threads. But depending on the internal implementation, this also could be dangerous. So, any information about Tomcat's implementation would be appreciated.
The primary implementation of ServletContext in Tomcat is the ApplicationContext class. If you look at the linked resource, you will see that the attributes are stored in a java.util.concurrent.ConcurrentHashMap instance. So, for ApplicationContext at least the getAttribute() and setAttribute() methods are thread-safe.