Using global variables in servlet evil? - java

I have a global variable called loginAttempt in a servlet class. What will happen to this global variable if two requests hit on the same time?What will happen is an unforeseeable event.
Is having global variables in servlet an evil ??
If i put the loginAttempt is side doPost() its initializing each time.

Yes.
Your variable is readable/writeable by any other class. You have no control to ensure that they all do sensible things with it. One of them could overwrite it/incorrectly increment it, etc
The is one instance of a servlet, per JVM. So may threads may try to access it concurrently. Because it is global, and you are not providing any synchronization/access control, it will not be thread-safe. Also, if you ever run the servlet in some kind of cluster with different JVMs, then the variable will not be shared between them and you will have multiple loginAttempt variables.
If you have to have it in the servlet, make it static but do not make it public. Provide getters/setters to access and update it. Learn about thread-safe programming so that multiple-threads can update it and read it safely.
Much better, store it in the servlet-context. This should be where you store servlet-wide data like this.

They are not evil as long as you understand that there is generally only a single instance of a servlet created and the global variable will be shared by all clients of that servlet - that is every request, on different threads at the same time and by multiple users at the same time.
I am guessing that your global variable loginAttempt is counting the number of login attempts then as long as this is done in a thread safe way it would be a reasonable way of counting the number of login attempts made on this servlet. This would be for all users though. If you want login attempts per user then you probably need to create a session and use the session context to store this sort of info.

Store it as a session attribute. Otherwise the global variable concept will screw you up totally.
Using session is a good idea as it's
1) If the web service is restarted, the session data is not lost
2) In a load balanced environment, the session data is stored in a central location, meaning any server can serve the request and have access to the session data.
So it's accessible yet it's hidden.

In a large number of concurrent access,You may want to pay attention to the thread safety problem of Servlet...and you can try the following methods to avoid this problem...
1、
public class loginAttempt extends HttpServlet implements SingleThreadModel {
...
}
2、
The second method:
Use the synchronized keyword
3、
Avoid the use of global variable

YES.
Global variables are shared with everyone

It depends, if your variable is read-only, it should be fine. But in most cases, global variables are evil. I can't give you a solution because I don't have your code but I am sure there is an alternative way.

In your usecase, it is beyond evil. loginAttempt will be shared by all threads accessing the servlet

First of all there is no terminology called global variable in Java. They are called class variable or instance variable.
Second, Yes its bad practice to have instance variable in the Servlet if you are assigning request or session scoped data as it will be shared by all threads.
You can use it for application-wide values, most often obtained from context parameters. or If the data never changes (immutable) like Constants.

Related

Need cache per request capability in Java

I am developing REST APIs using Java Spring framework.
When calling these APIs, I have a need to check for permissions, where I will need to make a call to the DB to get the permission data. The thing is, there are multiple areas checking for permission in a single request, and I do not want to make multiple calls to the DB, so I intent to cache the permission data just for that single request.
I have tried creating a request scoped bean, which works, but not for all cases. There are times where the request scoped bean cannot be created, for example when running a scheduled code using #Scheduled annotation, simply because it is not a request. Another case is when checking for permissions using WebSecurityConfigurerAdapter, the bean is also not yet created at that time.
So, I looked into another possible solution, which is this: https://github.com/rinoto/spring-request-cache. If I use this solution, I will need to remove the cache from threadLocal every time an operation is complete. I am not very comfortable of using this solution since I'm not an expert in Java, and I've read that it is not recommended to use threadLocal as cache.
What's the best way to achieve my goal? My ask is simple, cache some data only for that request. Is there any library that supports it?
I find it hard to believe that my ask is not a normal use case, or is it not a normal use case?
You can use ThreadLocal as a cache in this case. No need to clear. As per the documentation
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the {#code ThreadLocal} instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
eg: ThreadLocal<Map<String, Object>> THREAD_LOCAL_DATA = ThreadLocal.withInitial(HashMap::new)

Is there a way to bootstrap some actions to all my servlets?

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.

Singleton and Synchronised Servlet

I want to create a Servlet that processes input to a serial device and for that reason I want to make sure that exactly one instance of Servlet exists in the container at a time (irrespective of whether the container makes only one instance I have to make sure of it) and also the access to the serial port is either synchronised or serialised.
Any suggestions?
You don't need the servlet to be a singleton, you only need to be able to control access to the serial port. In fact even if you could enforce a single instance of the servlet class, the spec enables multiple users to access the servlet concurrently.
You could instead write a class that handles access to the port, encapsulating control by only allowing a single thread to access at a time. You'd then need to decide how you wanted concurrent requests to the servlet to behave (block, return some sort of 'serial port in use' error message, etc).
Suggestion: don't do that. Leave servlet management to the container, and use your own singleton for serial port processing.
Solution: you cannot, as you have no control over constructor. What you can do, though, (and what is a Very Bad Thing—don't tell anyone I said that) is to have a static field in a servlet, keeping a reference to the first instantiated instance. This way, all the instances of the servlet will be able to delegate the processing to this very first instance.
Again, just separating request processing from serial port processing will make things much more easier for both you and the container.

synchronizing global variables in a servlet

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.

Stateless session bean with instance variables

I have a stateless session bean that contains one public method, several private methods, and some instance level variables. Below is a pseudo code example.
private int instanceLevelVar
public void methodA(int x) {
this.instanceLevelVar = x;
methodB();
}
private void methodB() {
System.out.println(instanceLevelVar);
}
What I'm seeing is that methodB is printing values that weren't passed into MethodA. As best I can tell it's printing values from other instances of the same bean. What would cause this?
I should point out the code works as expected 99.9% of the time. However, the .01% is causing some serious issues / concerns for me.
I understand that if I had different public methods then I might not get the same bean back between calls, which would result in this behavior. However, in this case the only call is to the single public method. Will the container (Glassfish in this case) still swap the beans out between private method calls?
(edit) I renamed "class level" to "instance level" as this was causing some confusion.
When I read What is a Session Bean? section of the J2EE 1.4 tutorial:
Stateless Session Beans
A stateless session bean does not maintain a conversational state for a particular client. When a client invokes the method of a stateless bean, the bean's instance variables may contain a state, but only for the duration of the invocation. When the method is finished, the state is no longer retained. Except during method invocation, all instances of a stateless bean are equivalent, allowing the EJB container to assign an instance to any client.
In your case, the call to methodB() from methodA() will be on the same instance and is equivalent to this.methodB(). I'm thus tend to say that methodB() can't output something else that the value that what was passed to methodA().
This is confirmed by the first sentence in section 7.11.8 in the EJB 2.0 spec: "The container must ensure that only one thread can be executing an instance at any time". This means you cannot come to a situation where data (in your instance variables) from different clients (threads) will be mixed. You are ensured unique access to the instance variables until methodA() has returned!
That said, I'm not saying that you don't have a problem somewhere. But I don't think that your pseudo code is equivalent.
(EDIT: Having read some comments to the OP's question, there is now clearly a doubt about the pseudo code and semantic used. I'm clarifying possible consequences below.)
As underlined by Rocket Surgeon, what do you mean exactly by class variable? Do you really mean class variable as opposed to instance variable? If yes, the pseudo code doesn't reflect it but this will clearly lead to unpredictable behavior. Actually, from section 24.1.2 (and first point) in the EJB 2.0 spec, it is clear that you are not allowed to write data to a class variable (although you can do it). There must be a good reason for this :)
I would just not bother using instance variable in stateless session bean at all. Regardless of what the cause of the issue you have encountered, it's probably not something you would want to do anyway. Just try using local variables throughout or define instance variables in helper classes you are calling from the stateless session bean business methods.
The likely cause of the issue is that the container is using the same object in two requests (therefore two threads) at the same time. So the first thread gets to line that calls methodB and then the next thread gets to the code which calls methodB and then the first thread executes the call to methodB, causing the issue. That would explain the behavior, at any rate. It doesn't seem to fit the spec, but that could just be a bug.
In general, even if permitted, keeping state in the bean is not a great idea. It leads to confusion code and can easily lead to bugs where you forget to start over with your all your state on every method call.
It would be much better to just pass those objects around between methods, and that would avoid all issues.
Probably your are not properly reinitializing the instance variable.
Instance variables
In general we should not keep state in our stateless session bean. Objects referenced by instance variables, if not nulled after their use, are kept alive until the end of the request and even longer if our EJB container pools the session beans to reused. In the latter case we need to make sure that instance variable get properly reinitialized during a subsequent request. Therefore the use of instance variables may lead to the following issues:
during the same request, instance variable shared between different methods can easily lead to bugs where we forget to start over with the correct state on every method call
in case EJB container pools session beans and we may our code fails to properly reinitialize the instance variables we may reuse stale state set in a previous request
instance variables have instance scope which could introduce memory leak problems where space in the Heap is used to keep objects that are not (or should be not) used anymore.
Class variables
As for instance variables, class variables should not be used to keep shared state in Stateless session bean. This does not mean we should not use the static keyword but that we should use it with caution (e.g. define immutable constants, some static factory class, etc.)
Because this is very strange I performed a quick test with Netbeans and my local Glassfish 2.1.
Create a new project using Samples->Java EE->Servlet Stateless. This creates an enterprise project with a simple stateless bean and a servlet that uses it.
I modified the stateless bean to look like this, as close to your example as possible I think.
#Stateless
public class StatelessSessionBean implements StatelessSession {
String clName;
private void testNa() {
System.out.println(clName);
}
public String sayHello(String name) {
this.clName = name;
testNa();
return "Testcase";
}
}
This works as it should. I don't know what editor you're using, but if it's Netbeans it may be interesting to run it yourself.
It all hinges on what you mean by "class level variable". A class variable must have the static modifier. If clName doesn't, then each instance of your stateless session bean has its own copy of clName. Your Java EE server probably created a pool of two or more instances of the stateless session bean, and each of your calls to testNa() and sayHello() gets sent to an arbitrary instance.
I stumbled upon this question when I experienced the same problem. In my case, the private method actually sets the instance variable. What I have noticed is that sometimes the instance variable was already set, obviously from a previous request.
#Stateless
public class MyBean {
String someString;
public void doSomething() {
internalDoSomething();
}
private void internalDoSomething() {
if (someString != null) {
System.out.println("oops, someString already contained old data");
}
this.someString = "foo";
}
}
I guess it makes sense. When the container re-uses a cached instance, how should it know how to clear the variables...
To me, this is inline with and confirms both Pascal's reference to the EJB spec ("instance variables are supported") and Rocket Surgeon's recommendation ("don't do it, use local variables instead").
The problem with using Instance variables in stateless Beans.
According to the JEE specification that same stateless EJB instance might be shared with another client as well. The thumb rule is not to create instance variables in Stateless EJBs.
It might be possible the two clients accessing the application simultaneously are provided same EJB instance which would create problems since there is data inconsistency.
So it is not a good idea to use instance variables in stateless EJB beans .
I had similar issue because I used global static class variable in my ejb class and when I had concurrent stateless EJB running, variable was overwritten by other instances.
Static class fields are shared among all instances of a particular class, but only within a single Java Virtual Machine (JVM). Updating a static class field implies an intent to share the field's value among all instances of the class.
Hope help someone else :)

Categories

Resources