Could not initialize proxy - no Session - java

I've got an error that looks like this:
Could not initialize proxy - no Session
I'm working with java, hibernate and spring. This error comes up when trying to generate a PDF document, and I'm following the next steps to generate it on the fly and store in the database.
I sent a request to the app through a POST method. This generates the PDF on the fly and shows to the user.
Just after that request I send another, but through an ajax a request. This will generate the same PDF but will save it in the DB.
The error shows that a query could not be executed due to "could not initialize proxy - no Session" error.
Is there something that am I doing wrong, calling the same methods twice from the same user session? Could it be that the session is closed before both requests have finished?
Hope someone can help me to understand what is happening.

Your problem is that the hibernate Session lives only for one request. It opens in the start of the request and closes at the end. You guessed the answer: Hibernate session is closed before both requests are finished.
Exactly what is happening? Your entity objects live during both requests. How? They are stored in the HTTP session (which is a different thing called session) You don't give much information about the framework you are using, so I can't give you more details, but it is certain that the framework you are using somehow keeps your entities in the HTTP session. This is how the framework makes it easy for you to work with the same objects for more than one requests.
When the processing of the second request starts, the code is trying to access some entity (usually an element of a collection) that is lazily initialized by hibernate. The entity is not attached to a hibernate session, and so hibernate can't initialize the hibernate proxy before reading it. You should open a session and re-attach your entity to it at the beginning of the ajax request processing.
EDIT:
I will try to give a brief explanation of what is happening behind the scene. All java web frameworks have one or more servlets that handle the requests. The servlet handles each request (HttpRequest) by creating a new thread that will finally produce the response (HttpResponse). The method that processes each request is executed inside this thread.
At the beginning of the request processing your application should allocate the resources that it needs for processing (Transaction, Hibernate session etc). At the end of the processing cycle these resources are released (Transaction is committed, hibernate session is closed, JDBC connections are released etc). Lifecycle of these resources could be managed by your framework, or could be done by your code.
In order to support application state in a stateless protocol as HTTP, we have the HttpSession object. We (or the frameworks) put on HttpSession the information that remains relevant between different request cycles of the same client.
During the processing of the first request hibernate reads (lazily) an entity from the database. Due to lazy initialization some parts of this object's structure are hibernate proxy objects. These objects are associated with the hibernate session that created them.
The framework finds the entity from the previous request in the HttpSession object when you try to process the second request. Then it is trying to access a property from a child entity that was lazily initialized and now is a hibernate proxy object. The hibernate proxy object is an imitation of the real object that will ask its hibernate session to fill it with information from the database when someone tries to access one of its properties. This what your hibernate proxy is trying to do. But its session was closed at the end of the previous request processing, so now it doesn't have a hibernate session to use in order to be hydrated (filled with real info).
Note that it is possible that you have already opened a hibernate session at the beginning of the second request, but it isn't aware of the entity that contains the proxy object because this entity was read by a different hibernate sesion. You should re-attach the entity to the new hibernate session.
There is a lot of discussion about how to re-attach a detached entity, but the simplest approach right now is session.update(entity).
Hope it helps.

Related

Hibernate Contextual sessions

What's the difference between ManagedSessionContext and ThreadLocalSessionContext both has a ThreadLocal in their implementation for maintaining sessions
ThreadLocalSessionContext - It takes care of the hibernate session management activities like :
Creating a session if one doesn't already exist.
Binding the session to the ThreadLocal, so that sessionFactory.getCurrentSession() returns this bound session and unbinds it once the transaction is completed.
Flush and close the session at the end of transaction complete.
ManagedSessionContext - Responsibility of session management activities like above are handled by some external entity (generally some form of interceptor, etc).
In both the cases the session is stored in the ThreadLocal though.
But the call to bind/unbind of the session and especially when to call flush and close on the session are defined via the external entity.
This gives more flexibility, for example, in the case of ThreadLocalSessionContext, the session is closed automatically when the transaction ends and it is not possible to leave the session open for multi-request conversation type of requirements.
In case of ManagedSessionContext, we can implement multi-request conversation (a.k.a session-per-conversation model) the same session needs to be kept open and should be reused across the user requests. So in the first user request we insert/update/delete some entities and in the next request we do some more operations and finally at the end of third interaction we want to commit the data.
Quoting from Managing the current Session section
When a conversation starts, a new Session must be opened and bound with ManagedSessionContext.bind() to serve the first request in the conversation. You also have to set FlushMode.MANUAL on that new Session, because you don’t want any persistence context synchronization to occur behind your back.
All data-access code that now calls sessionFactory.getCurrentSession() receives the Session you bound.
When a request in the conversation completes, you need to call Managed-SessionContext.unbind() and store the now disconnected Session somewhere until the next request in the conversation is made. Or, if this was the last request in the conversation, you need to flush and close the Session.
To represent that pictorially,
Session scoping with ThreadLocalSessionContext
Session scoping implemented for Session-per-conversation using ManagedSessionContext
You can go through the Listing 11.5 of this link for a sample implementation an interceptor that manages the session for session-per-conversation model.

Maintaining a transaction flow using Jersey REST

I am pretty new to the REST world and we are trying our hands at migrating our application to a REST based architecture. We are working on a proof of concept and we need to come up with a working proof that what we are set to achieve can be done using REST.
In our architecture, the front end screens would use Angular and would call REST services to open up a customer session and perform/maintain transactions within that session and when the session is complete, the session details (i.e. all the customer transactions within the customer session) would be sent over for commit to the DB. We only want to write to the DB after customer completes all transactions within a session. In other words, a commit to the DB happens only when the session ends.
I am hoping to get some directions on how best to perform the below steps in our Java classes.
1) Browser initiates a request to open a new customer session. A session POST service is used to generate a new session ID. The session ID is sent back as response to the browser.
Question --> What is the best way to maintain this session ID value in my Java classes?
2) Customer transactions are performed within the session. For each transaction processed a transaction POST service is used to save the transaction information along with the session information.
Question --> In my Java classes what is the best way to maintain this transaction information and how best do I associate this transaction information with the session information that was created by the previous session POST information? The client would maintain the session ID but on the service side I need to be able to map the transaction with the session ID so that I can send back a combined session payload that includes session information and the transaction within that session.
3) A customer can perform some more transactions and each transaction performed would be a transaction POST request which would have to get associated with the session id created before. Each additional transaction performed would have to be associated to the session id on the service side such that when I do a GET on the session id, I need to get the session details along with all transactions within that session.
4) Finally when the session is complete the information from the session and the session payload on the service side (along with all the transactions) will commit to the DB.
I am just looking for some general guidance on how best to do this using my Java classes and Jersey REST.
Any pointers would be appreciated.
Thanks
Ali.
Basically this question isn't easy and requires a lot of writing, however I'll try to reply.
First of all remember that REST is stateless - it means that there's no session and client needs to be authorized with every request. This is a separate topic but a nice authorization method in REST is JSON Web Token.
Secondly REST is about nouns - not verbs. Thus you should avoid URLs like /session/{sessionId}/close/ but try to model the domain using nouns and default HTTP operations: POST (create), PUT (update), GET (read), DELETE (remove).
I guess that session and transactions is just an abstraction I will show you how to model it on an example of shopping cart. In all examples I doubled the URLs - with /users/{userId}/ prefix to show you can refer to resources in many different ways
Create a shopping cart (creating a session)
POST /shopping-carts/
POST /users/{userID}/shopping-carts/
Request: may be empty or should contain necessary details about the cart
Response: must contain a newly-created shoppingCartID
{
"shoppingCartID": "1qaz2wsx"
...
}
Add an item to a shopping cart (create a transaction)
POST /shopping-carts/{shoppingCartID}/items/
POST /users/{userID}/shopping-carts/{shoppingCartID}/items/
Request: contains details about an item being added
Response: returns a newly-added item along with its unique ID
Pay for the shopping cart (commit the transactions)
POST /payments/
POST /users/{userID}/payments/
Request: must contain a shoppingCartID
{
"shoppingCartID": "1qaz2wsx"
...
}
Response: Contains details about newly-created payment
{
"paymentId": "3edc4rfv"
...
}
I know that this is a general answer but it's difficult to give a precise answer for such a wide question.
EDIT (after a discussion in comments)
In my opinion the DB should be used to keep the transactions in a temporary table before they are approved. Even if you don't want to use a DB any other persistent store is highly recommended - imagine what could happen in case of a server restart when transactions are not approved, you will lose all the data.
The options I see:
In memory. You can write a simple in-memory structure with a synchronized access. In the most simple case just plain old HashMap will be enough. Mind the fact that keeping data this way is risky, the can be erased very easily.
Use file system. If you don't want to use DB you can use file system to keep the transactions data while they're uncommitted. After adding a new transaction it's written to a file. On commit file is read and all transactions are saved to DB. A synchronized file access is also very important here. When it comes to data format you can use JSON, XML, even plain java serialization.
The last idea that comes to my head is to use an in memory DB, such as Redis. The data will be erased on a system reboot so they're less likely to be deleted, however this is not safe in my opinion as well. Such DB is much easier to use/maintain than traditional DB.
It all depends what are you trying to implement. I can't imagine a scenario where uncommitted transactions can be simply removed and nothing happens - it seems that there's a must for persistent storage. However the ideas above might be useful as well.

Best practice for querying inside event listeners in Hibernate

We have a FlushEventListener to do audit functionality. While updating some entity, hibernate will callback our audit code just before flushing. The audit code needs to query the database.
If we try to do it in the same session apparently we mess up the session's state: we get a NullPointerException from inside hibernate, at some point when it's validating naturalIds inside a class named NaturalIdXrefDelegate.
We currently solved it by opening a new session for the audit query. The problem with this is we're losing the benefit of getCurrentSession (a session for the whole request, managed by hibernate). This way we're going back to opening one session per query.
Is there an elegant solution for this or we basically need to re-implement getCurrentSession to manage our own session #2 in the request?
You don't have to open new session. It's enough to temporarily disable flush.
Session session = entityManager.unwrap(Session.class);
session.setHibernateFlushMode(FlushMode.MANUAL);
// do your db stuff
session.setHibernateFlushMode(FlushMode.AUTO);
It's actually a lot faster than
session.getSessionFactory().openSession()
Which works to btw.

Generating Own Session Id in JSF

I have a web application in which we use JSF framework.
I have been diving deep into the security part for web application and hence I was looking to generate my own unique session ID(using encryption algorithm and assign it to every new session which gets created once user logs in.
Can anyone please guide me on how to set manual generated session id in session and ensure with each request that session id is transmitted.
Thanks.
I really doubt you'll generate session IDs that are more secure than the ones generated by the container, but here's what you could do, without using any container-specific extension.
Create a servlet filter which intercept every request to the server.
When a request comes in, check if a session already exists for this request (using getSession(false)). If one exists, then extract your specific cookie MY_SESSION_ID from the request, and compare its value to the one that is stored in the session. If they don't match, reject the request.
If the session doesn't exist, then create it (using getSession(true)), generate your super-secure session ID, store it as a session attribute and add the cookie MY_SESSION_ID to the response.
This has the disadvantage of creating a session automatically, even if it's not strictly needed. But that's the case most of the time when using JSPs of component frameworks.
Attempting to do this at the JSF application layer is unlikely to be successful; I would perform this task at a lower level API. I am assuming a servlet container.
I can think of two approaches:
do this at a container level via a server-specific SPI (if one even exists)
do this by rewriting requests/responses via a servlet Filter
There is insufficient information to comment on the viability of the first approach.
In the second, you would have to determine the name of the session cookie (it is usually JSESSIONID, but does not have to be). Your API would:
map the filter to all application requests
maintain a map of container session ids to "secure" ids
use the filter to rewrite any session cookie in the request with the session id
use the filter rewrite any session cookie in the response with the secure id
use a listener to remove invalid sessions from the map to avoid memory leaks

Hibernate sessions REST performance/security

Intro
I'm bulding a REST web service using Hibernate and Jersey to supply JSON data to mobile clients. I have a general question about how to deal with Hibernate sessions internally. There are two different approaches(A,B) I'd like to discuss.
Approaches
A. Someone told me I should open a new session per user, let it open for the whole web session of the user and finally close this session after the user stopped using my web service. I was told it would be a better approach from the view of security and performance.
Though I've read that: "Sessions are irrelevant" Common REST Mistakes, 6.
B. Right now I'm using a SessionFactory to open a session in my service classes and close this session immediately after a query is done. My web service is only using GET and POST requests. There is not PUT or DELETE. I don't need any user authentication (like oAuth) to request data. Therefore I don't think it's necessary to use Transactions
Here is an Example of my Service class:
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Query query = session.createQuery("from RoomEntity");
#SuppressWarnings("unchecked")
List<RoomEntity> list = (List<RoomEntity>) query.list();
session.close();
Questions
Would be great to hear your opinion about my following questions:
What would be the best practice? Which approach do you follow?
What do you think about the performance matter?
What do you think about the security matter?
I don't like A. It makes your service stateful and how do you know when a user has finished with your services anyway?
The general rule with Hibernate and web apps is to use a single session per http request. Most REST service GET requests map pretty simply to a single DB query as you have demonstrated with B, so this is the way to go.
You should be having one Session per request, its called Onit of Work pattern. There are frameworks out there that support this implementation one of them is Spring(I would recomend to use it and not try to reinvent a wheel). You can read about it here.
I am in a similar situation. Based on the JBOSS documentation a session per request within Jersey appears to be valid. You could use an implementation of the ContainerRequestFilter in Jersey to open up a hibernate session and then close it with commits in an implementation of the ContainerResponseFilter.

Categories