Scenario:
I have #Singleton UserFactory (#Stateless could be) , its method createSession() generating #Stateful UserSession bean by manual lookup.
If I am injecting by DI #EJB - i will get same instance during calling fromFactory() method(as it should be)
What I want - is to get new instance of UserSession without preforming lookup.
Q1: how could I call new instance of #Stateful session bean?
Code:
#Singleton
#Startup
#LocalBean
public class UserFactory {
#EJB
private UserSession session;
public UserFactory() {
}
#Schedule(second = "*/1", minute = "*", hour = "*")
public void creatingInstances(){
try {
InitialContext ctx = new InitialContext();
UserSession session2 = (UserSession) ctx.lookup("java:global/inferno/lic/UserSession");
System.out.println("in singleton UUID " +session2.getSessionUUID());
} catch (NamingException e) {
e.printStackTrace();
}
}
#Schedule(second = "*/1", minute = "*", hour = "*")
public void fromFactory(){
System.out.println("in singleton UUID " +session.getSessionUUID());
}
public UserSession creatSession(){
UserSession session2 = null;
try {
InitialContext ctx = new InitialContext();
session2 = (UserSession) ctx.lookup("java:global/inferno/lic/UserSession");
System.out.println("in singleton UUID " +session2.getSessionUUID());
} catch (NamingException e) {
e.printStackTrace();
}
return session2;
}
}
As I understand, calling of
session.getClass().newInstance();
is not a best idea
Q2 : is it true?
#
Update
Goals
In reality the goal is to create some SessionsFactory that that would managed user`s sessions (this is web services users)
The Session #Statefull bean :
#Stateful
//Destroying outomaticly after 30 minuts inactive
#StatefulTimeout(180000)
#LocalBean
public class UserSession {
//represent creation time, used by scheduler for destroying session
private GregorianCalendar creationDate;
private UUID sessionUUID;
private String userId;
private String state;
//TODO change to xml
private String histrory;
public UserSession() {
}
#PostConstruct
private void initSession(){
//getting construction date
creationDate = (GregorianCalendar) Calendar.getInstance();
//generationg session id
sessionUUID = UUID.randomUUID();
}
#PreDestroy
private void releaseResource(){
creationDate =null;
sessionUUID = null;
userId =null;
}
#Remove
public void destroySession(){
}
public UUID getSessionUUID() {
return sessionUUID;
}
public GregorianCalendar getCreationDate() {
return creationDate;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getHistrory() {
return histrory;
}
public void addHistroryEntry(String entry) {
//TODO add history entry
}
}
In factory methods I want just create new instance of #Statefull UserSession and to manage number of created sessions for each user, and call destroySession() after some period (30 minutes)
I need to track the history of user`s sessions requests , and persists there history later..
So I think #Statefull bean should suet my needs. But it looks like the lookup by JNDI name is the only chance to be shore that new ejb will be created. I am searching for possibility
to inject new instance of ejb without lookups, and maybe possibility to get collection of currently created instances of my #Statefull UserSession instead of keeping thrm in some map/collection.
Q3: so.. only JNDI will help me to create new instance of ejb ?
Q4: Is it possible to get collection of some ejb`s instances from container?
I am using glassfish v3, ejb 3.1.
Q1: how could I call new instance of #Stateful session bean?
You must not inject a Stateful Session Bean into a stateless object such as Stateless
Session Bean or Servlet that may be shared by multiple concurrent clients, you should use JNDI instead. Period.
To be honest, I'm not sure to understand what you are doing and I don't see important steps such as removal of your Stateful Session Beans. You are likely going to run out of memory or cause a lot of disk IO as the container that will try to passivate/activate instances to save memory.
Q2 : is it true?
You can call new but don't expect to get something else than a simple Java class i.e. don't expect to get a managed object i.e. don't expect to get an EJB. I don't think that this is what you want.
Sorry if this doesn't help much but as I said, I don't really understand what you're trying to achieve. You should maybe start to explain your goal first, I don't have the feeling that you are on the right path.
Related
I'm trying to implement the "One-session-per-http-request" pattern with Hibernate, and it works for the 1st request : The servlet's doGet() method opens the session, gets some stuff, and closes the session.
But when I refresh the browser, My DAO Singleton instance (whose constructor gets the session from the SessionFactory) gets called a second time, but still uses the old session object (the singleton constructor is NOT called again). I then obtain a "Session is closed" error.
I guess that the singleton instance must be kept in cache between HTTP requests, so : How can I get the DAO singleton constructor called again ? (or another elegant solution to have the fresh SessionFactory session object ?)
Thank you very much
The servlet :
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// Gets the session, eventually creates one
Session s = HibernateUtil.currentSession();
// Gets data from singleton DAO instance
MySingletonDAO o = MySingletonDAO.getInstance();
List<Stuff> stuff = o.getAllTheStuff();
// send it to the view
request.setAttribute("foo",stuff);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(vue);
dispatcher.forward(request, response);
}
/* error handling blah blah */
finally {
// closing the session
HibernateUtil.closeSession();
}
MySingletonDAO.java :
public class MySingletonDAO {
// Usual singleton syntax
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private Session session;
private MySingletonDAO() {
session = HibernateUtil.currentSession();
System.out.println("This constructor is called only on the first HTTP transaction");
}
public List<Stuff> getAllTheStuff() {
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
A classical thread-safe HibernateUtil.java :
public class HibernateUtil {
private static final SessionFactory sessionFactory;
public static final ThreadLocal session = new ThreadLocal();
static {
try {
// Creates the SessionFactory
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException he) {
throw new RuntimeException("Conf problem : "+ he.getMessage(), he);
}
}
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// Opens a new Session, if this Thread has none
if (s == null || !s.isOpen() ) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
What you're asking for doesn't make sense: if the constructor of the singleton was called at each request, it wouldn't be a singleton anymore. The session is indeed closed at the end of the request, but the DAO keeps a reference to the session, instead of getting it from your util class every time it's called.
Your DAO code should be
public class MySingletonDAO {
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private MySingletonDAO() {
}
public List<Stuff> getAllTheStuff() {
Session session = HibernateUtil.currentSession();
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
That said, transactions should be handled declaratively, and should be handled at the service layer rather than the DAO layer: a transaction typically uses deveral DAOs, the entities returned by the DAO should stay managed, and all the accesses and modifications made to these entities should be made inside the transaction.
I strongly recommend using a Java EE container, or Spring, to handle the transactions and the session handling for you. You should also use the standard JPA API rather than the proprietary Hibernate API.
I'm adapting my project to utilize DI - Dagger in particular. I have no problems injecting classes, but how do you 'inject' a runtime generated variable?
Say, I want to store user's login session object that contains data such as api-token, loggedUsername and whatnot inside. This object is generated at runtime when the user has successfully logged in, in another class responsible for doing so.
As an illustration, what I want is to simply do something like this:
public class FooPresenter {
...
Session mSession;
#Inject FooPresenter(Session session, ...) {
mSession = session;
...
}
...
}
Thanks in advance!
I ended up declaring a method to obtain my session, which I kept as a String in SharedPreferences after a successful login, in a Dagger module class.
That way, I could just inject the session anywhere it's needed.
Here's my SessionDomainModule:
#Module(
library = true,
complete = false)
public class SessionDomainModule {
// TODO: Rethink this implementation.
#Provides
public Session provideSession(Application application) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
String sessionJString = preferences.getString(AppConfig.PREF_KEY_CURRENT_SESSION, "");
Session session;
if(!"".equals(sessionJString)) {
return new Gson().fromJson(sessionJString, Session.class);
}
return null;
}
...
}
By doing that, I could achieve what I wanted and codes in the like of those on my question could finally work.
You can have a SessionModule which keeps a reference to your current Session:
#Module
class SessionModule {
#Nullable
private Session mSession;
#Provides Session provideSession() {
return mSession;
}
void setSession(Session session) {
mSession = session;
}
}
You will need a reference to this SessionModule however to update the session object.
Another way is to create a (singleton) SessionProvider, which does nothing more than holding the Session:
#Singleton
class SessionProvider {
Session session;
#Inject
SessionProvider() {
}
}
Then, instead of injecting the Session instance, you would inject the SessionProvider, from which you can retrieve / update the Session.
Could anyone help me? There is a SessionScoped Managed Bean and one Stateless Ejb and one other Stateful Ejb..
The serachCustomer() method in the MB call the injected DaoEjbTst searcCustomer() method which return with an instance of BCus entity object. I injected in to Stateless DaoEjbTst Ejb the other Stateful CustomerSession EJB and when the entity instance is ready in the DaoEjbTst EJB i call the CustomerSession EJB setActualCustomer method and i give as paramter the entity instance for this method and try to store it... Then when i try to get this "stored" entity instance with another showTstDate() method in the ManagedBean it's throws NullPointer Exception.. And i dont know why.. Why doesn't exist the public BCus actualCustomer paramter in the stateful ejb? I tryed to create #PreDestroy and #PrePassivate and #Remove methods in the Stateful Ejb to check if the container remove it but this methods never invoked by the container.. So i'm sure the ejb exist.. but inspite of this i can't access it :( I don't use interfaces.
Here is my managedbean:
#EJB
private DaoEjbTst daoEjb;
#EJB
private CustomerSession customerSession;
public void serachCustomer() throws IOException {
FacesContext ctx = FacesContext.getCurrentInstance();
if (daoEjb.searcCustomer(custNo)) {
ctx.getExternalContext().redirect("showCustomer.xhtml");
}
else {
ctx.getExternalContext().redirect("test.xhtml");
}
}
public String showTstDate() {
log.info("MB EJB EXIST: " + customerSession);
return "Test: " + customerSession.getActualCustomer().getCustName();
}
Here is my DaoEjbTst:
#Stateless
public class DaoEjbTst {
private final Logger log = Logger.getLogger("DaoEjbTst.class");
#EJB
private CustomerSession customerSession;
public CustomerSession getCustomerSession() {
return customerSession;
}
public void setCustomerSession(CustomerSession customerSession) {
this.customerSession = customerSession;
}
#PersistenceContext(unitName = "TestAppPU")
private EntityManager em;
public boolean searcCustomer(String custNo) {
try {
BCus cus = (BCus) em.createNamedQuery("BCus.findByCustomerno").setParameter("customerno", custNo).getSingleResult();
log.info("DAOEJB: " + cus);
customerSession.setActualCustomer(cus);
return true;
}
catch (NoResultException e) {
log.info(e.getMessage());
return false;
}
}
And here is my CustomerSession EJb:
#Stateful
public class CustomerSession {
public BCus actualCustomer;
private final Logger log = Logger.getLogger("CustomerSession.class");
public BCus getActualCustomer() {
return actualCustomer;
}
public void setActualCustomer(BCus actualCustomer) {
this.actualCustomer = actualCustomer;
checkTst();
}
public CustomerSession() {
}
}
I think that CustomerSession bean injected in ManagedBean isn't the same bean instance that is injected in DaoEjbTst. So invoking:
customerSession.getActualCustomer()
in ManagedBean simply returns null because ActualCustomer field was not set for this particular bean instance. It was set in DaoEjbTest but this is different instance of CustomerSession. So:
DaoEjbTst.getCustomerSession().equals(ManagedBean.getCustomerSession())
gives false.
When you look into specification EJB 3.1 (section 3.4.7.1) you see:
A stateful session object has a unique identity that is assigned by the container at the time the object is
created.
Basically what you should do is to setActualCustomer for the instance of CustomerSession bean in ManagedBean with value that is found in DAO's searcCustomer() method. However storing stateful session bean inside stateless bean is a very bad idea and I suggest you to rethink your architecture.
I have a web service DocGenerationServiceImpl that inserts (for every format) a record in the table using DocRepository and object representing the record as DocFileDO. In the for-loop, I can get the id of the record that was created in the table. For each record, I will call the executor's execute method where DocGenTask will search for the record given the id. However, for example, there are 3 formats, the DocGenTask is able to get only the last record. The first 2 it cannot find. Although it's using hibernateTemplate. Can please advise?
#RestfulService
#Controller
#RequestMapping("/docs")
public class DocGenerationServiceImpl {
#Autowired
private TaskExecutor taskExecutor;
#Autowired
private DocRepository docRepository;
#RequestMapping(value = "/generate", method = RequestMethod.POST)
#ResponseBody
public String generatedDocFile(DOCParam param) {
for(String format : param.getFormatList()) {
DocFileDO docFileDO = new DocFileDO();
...
docRepository.saveDocFile(docFileDO);
log.debug("docFileDO id = " + docFileDO.getId());
DocGenTask task = new DocGenTask(docFileDO.getId());
task.setDocRepository(docRepository);
taskExecutor.execute(task);
}
}
}
#Repository
public class DocRepository {
#Autowired
private HibernateTemplate hibernateTemplate;
public DocFileDO saveDocFile(DocFileDO docFile) {
hibernateTemplate.save(docFile);
hibernateTemplate.flush();
return docFile;
}
public DocFileDO getDocFile(Long docFileId) {
return hibernateTemplate.get(DocFileDO.class, docFileId);
}
}
public class DocGenTask implements Runnable {
public void run() {
generate();
}
private void generate() {
DocFileDO docFileObj = docRepository.getDocFile(docFileId);
}
}
A couple of things
Don't use HibernateTemplate it should be considered deprecated as of Hibernate 3.0.1 (which was released somewhere in 2006). Use the SessionFactory directly and use the getCurrentSession() method to get a hibernate Session to operate on.
You don't have transactions setup (judging from the snippets), to work with a databse you need proper transaction setup.
Your controller is doing much, all of this should be inside a service.
The first refactor your repository
#Repository
public class DocRepository {
#Autowired
private SessionFactory sf;
public DocFileDO saveDocFile(DocFileDO docFile) {
Session session = sf.getCurrentSession();
session.save(docFile);
return docFile;
}
public DocFileDO getDocFile(Long docFileId) {
return sf.getCurrentSession().get(DocFileDO.class, docFileId);
}
}
Now your code will probably fail due to improper transaction setup. Add #Transactional to all the methods (or class) that need a transaction (like the saveDocFile method).
As mentioned you probably should move the code found in the controller to a service. The controller should be nothing more then a thin integration layer converting from the web to an internal representation of something and then kick off a service/business method somewhere. This service-/business-method is also your transactional unit-of-work it either all succeeds or all fails.
Ok, I read bunch of articles/examples how to write Entity Manager Factory in singleton.
One of them easiest for me to understand a bit:
http://javanotepad.blogspot.com/2007/05/jpa-entitymanagerfactory-in-web.html
I learned that EntityManagerFactory (EMF) should only be created once preferably in application scope.
And also make sure to close the EMF once it's used (?)
So I wrote EMF helper class for business methods to use:
public class EmProvider {
private static final String DB_PU = "KogaAlphaPU";
public static final boolean DEBUG = true;
private static final EmProvider singleton = new EmProvider();
private EntityManagerFactory emf;
private EmProvider() {}
public static EmProvider getInstance() {
return singleton;
}
public EntityManagerFactory getEntityManagerFactory() {
if(emf == null) {
emf = Persistence.createEntityManagerFactory(DB_PU);
}
if(DEBUG) {
System.out.println("factory created on: " + new Date());
}
return emf;
}
public void closeEmf() {
if(emf.isOpen() || emf != null) {
emf.close();
}
emf = null;
if(DEBUG) {
System.out.println("EMF closed at: " + new Date());
}
}
}//end class
And my method using EmProvider:
public String foo() {
EntityManager em = null;
List<Object[]> out = null;
try {
em = EmProvider.getInstance().getEntityManagerFactory().createEntityManager();
Query query = em.createNativeQuery(JPQL_JOIN); //just some random query
out = query.getResultList();
}
catch(Exception e) {
//handle error....
}
finally {
if(em != null) {
em.close(); //make sure to close EntityManager
}
//should I not close the EMF itself here?????
EmProvider.getInstance().closeEmf();
}
I made sure to close EntityManager (em) within method level as suggested. But when should EntityManagerFactory be closed then? And why EMF has to be singleton so bad??? I read about concurrency issues but as I am not experienced multi-thread-grammer, I can't really be clear on this idea.
EntityManagerFactory instances are
heavyweight objects. Each factory
might maintain a metadata cache,
object state cache, EntityManager
pool, connection pool, and more. If
your application no longer needs an
EntityManagerFactory, you should
close it to free these resources.
When an EntityManagerFactory closes,
all EntityManagers from that factory,
and by extension all entities managed
by those EntityManagers, become
invalid.
It is much better to keep a factory
open for a long period of time than
to repeatedly create and close new
factories. Thus, most applications
will never close the factory, or only
close it when the application is
exiting.
Only applications that require
multiple factories with different
configurations have an obvious reason
to create and close multiple
EntityManagerFactory instances.
Only one EntityManagerFactory is
permitted to be created for each
deployed persistence unit
configuration. Any number of
EntityManager instances may be
created from a given factory.
More than one entity manager factory
instance may be available
simultaneously in the JVM. Methods of the EntityManagerFactory
interface are threadsafe.