I inherited some legacy Business Objects code that needs some TLC. The code is a Servlet. A new IEnterpriseSession is created for every new request into the Servlet. My initial concern is that creating a new IEnterpriseSession for every request seems wasteful and leads to slow requests. Please note that this is an admin IEnterpriseSession, its used over and over again for administrative purposes.
So my question is, is it OK to just create one of these during init() for the Servlet and use it over and over again for as long as the server is up? Can it be shared across threads or does it have to be ThreadLocal? Is there a known timeout exception that is thrown if the session grows stale?
The IEnterpriseSession can be cached and reused. There is a timeout setting inside Business Objects' CMC that can end the session, so do pay attention to if the session itself is valid before using it, if you go about caching. The session itself is an actual login to the Business Objects system so should be unique per user.
Related
I've sent the same request to a Spring MVC project with two browsers, but I got the same threadlocal, so the instances in threadlocal are the same.,Why?
Threadlocal is bound to a thread / process, not to a session. JVM does not really know or care about the concept of web sessions, that's a higher level of abstraction.
It is well possible that two web requests with two sessions are handled by the same thread. Most servers use a pool of threads that they reuse rather than create a new thread for each request or even session. If the processing of the first request leaves something in the threadlocal after it's done processing the request, well, that's what the next request will find there.
Store the data you need to keep per-session in HttpServletRequest.getSession() instead.
I have 2 servers.
Server A has a cron system, which given a trigger requirement, calls the Server B through a servlet
In server B, when receiving the server A's call, i store serveral informations on the HttpSession and then i start a new thread, so i could free server A.
I have found, thought logs, that in several cases, when the thread in Server B is reaching the HttpSession, the values that were set before are different. They are not null or blank, they have acctual values, but not the ones i put.
The server A fires like, 30 notifications each 5 minutes. This means i will have several concurrent threads.
Why is the HttpSession being overriden by another thread?
Section 2.3.3.4 of the Servlet Specification v 3.0 says,
If a thread created by the application uses the container-managed
objects, such as the request or response [or session] object, those objects
must be accessed only within the object’s life cycle [...].
HttpSession objects are certainly container-managed objects, but their life cycle is not clearly defined by the Servlet specification. It seems plausible, however, to consider the life cycle to end when the session has been invalidated, whether explicitly or by time out, and no request belonging to that session is being serviced. After that point, if you continue to access the session object then all bets are off. In particular, the container is permitted to cache and re-use managed objects, including session objects.
If your server A does not participate in session tracking, then every request will be assigned to a new session, and each one's lifetime will be a single timeout period. In this case, you could consider setting the [default] timeout long enough to ensure that sessions do not time out during the course of one computation (but see below). If your server A does participate in session tracking, on the other hand, then the session object will be open for modification on each request.
Whether server A participates in session tracking or not, however, it is poor form for an application thread such as those you start manually to access container-managed objects. It would be better all around to use a different mechanism to provide data to them.
I lately observed a problem in my code, I opened a hibernate session but forgot to close it. Although I fixed it but I can't seem to understand the impact of this mistake I did.
This code was in HTTP service, I need answers for two cases:
The container spawns a new thread when a request comes
It fetches from thread pool
I have read in other posts that session is bound to thread, so what I have inferred from that is if a new thread is spawned in each request and I have left a session open in one of them. It will be then destroyed when request gets completed. I dont know I am right or not.
It depends of what you use to control a session life cycle.
If you use a "session per request pattern" with, for an example, OpenSessionInViewFilter, a session will be closed by a filter. You can use your own filter to control a session as well.
If you don't use filters or similar stuff you should always close a session.
Threads that process requests know nothing about Hibernate session.
SessionFactory.openSession() always open a new session.
SessionFactory.getCurrentSession() do a check, if the current session exists — return it, if the current session doesn't exist — create a new one. A meaning of "current session" depends of a session factory parameters. In the classical case, a session is bounded to the thread (as you describe), but it can be bounded to the transaction, for an example.
I'm trying to implement a tricky thing and need some fresh ideas.
The problem is:
Imagine Component1, that is performing some action for each User in a collection.
Just like
for (User user : users) {
doSomeStuff(user);
}
These actions have some common parts, that are time-consuming, so the goal is to perform them only once (they include some database queries and so on).
Imagine one of this time consuming methods:
public Object buildSomething(Object context) {
// some business logic here
}
The idea was to store the result and share it for other users, like this
public Object buildSomething(Object context) {
if (sharedResource.contains('something') {
return sharedResource.get('something');
} else {
// some business logic here
sharedResource.put('something', something)
return something;
}
}
The riddle is - how to implement this shared resource?
Must say, this is a huge multi layer web application and we can't just change doSomeStuff method and add a context holder parameter there, or something similar.
I analyzed the following variants:
Session scope bean (the one that makes the buildSomething stuff)
Problems: User can logout from application, login with another username/pass, he will still have same Http session and that means he will get the same bean with previous request state
upd: Another problem of using session scope is spring based thread pool scheduler, that can invoke Component1 without any http session.
ThreadLocal variable
Problems: We are in a web application context, and when thread is returned to pool, it can be used for other user requests
I tried to find a workaround for second problem and my question is:
Is it possible to analyze stack trace elements and ensure, that two invocations of buildSomething method were caused by a single user request?
Tx for attention
I think session scoped beans are the better solution. You can manage when a session is destroyed or created. You need to call "HttpSession.invalidate()" when a user logs out.
There is a good article about session lifecycle management.
http://docstore.mik.ua/orelly/java-ent/servlet/ch07_05.htm
You also can use the HttpSession utils to store information in session (such as username).
Salut!
I decided to post my solution to this problem, that now works on production server.
It is based on a ThreadLocal variable, that holds the information in a request scope.
The original problem was in a fact, that different clients can reuse a single thread, because threads are stored in a pool. This fact didn't allow to use session beans and thread locals as is.
So I had to review all entry points, where user requests come to my application layer. When I detected a request, I cleaned thread local context for a request. It worked, because there are only few ways for request to come to application layer: it could be a service request from another layer, that could be intercepted with AOP and a scheduler job, that can be intercepted by custom ThreadPoolExecutor.
I know that every request is served by a servlet thread, but will it be possible for one user session, two request served by two different thread?
If the situation above really happens, what about thread local variable stored by first request-serving thread be read by second request-serving thread?
I'm afraid that if I store user credential in Spring Security's SecurityContextHolder(which uses thread local variable) in first thread, the second thread will not be able to access the user credential...
I know that every request is served by a servlet thread, but will it be possible for one user session, two request served by two different thread?
Yes, that's possible.
I'm afraid that if I store user credential in Spring Security's SecurityContextHolder(which uses thread local variable) in first thread, the second thread will not be able to access the user credential...
Security is established separately for each request by Spring, you do not have to handle this yourself.
No, one request will not be served by several threads. What can really happen is serving of 2 requests by one thread. This is the reason that you should be very careful using thread local variables yourself. However you can trust Spring framework: it does things right. It can for example use session or request ID when using thread local, so 2 request being processed by one thread will not be confused.
Two separate requests of the same user are handled (most likely) by two different threads.
I am not sure what Spring does, but the Servlet api provides a way to retrieve data that is specific to the user session (how the server tracks the session is irrelevant, but have a look at cookies and url rewriting).
Now, If I wanted to have the user credentials on a threadlocal variable (which is not unusual, as the ThreadLocal pseudo-singleton is the most convenient way of injection I know), I would store them on the users HttpSession (which is persistent across all requests of the same user) and use a servlet filter to put them on the threadlocal at the beginning of each request.
I hope this makes things a bit clearer for you. I find it is better to know what's happening under the hood even when using the most up to date framework :)