Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    DMI question

    Hi,

    I need an advice on using DMI with JPA2.

    I need to create and close entityManager for each request in order to pick up database changes made by others.
    One way to do it is to close the entity manager at the end of DMI method but this causes en exception because of lazy loading of JPA(currently hibernate) needs to have the entity manager which loaded it open. I need to close it after datasource serialized data from entities.

    Is there any callback I could use? Is there a better way?

    At the moment I assume that DMI calls use thread pool at the server side. Am I correct? Or will DMI invocation create a new thread each time?

    At the moment my implementation is
    Code:
    	static {
    		emf = Persistence.createEntityManagerFactory("smartRISE");
    		threadLocal = new ThreadLocal<EntityManager>();
    		logger = Logger.getLogger("smartRISE");
    		logger.setLevel(Level.ALL);
    	}
    
    	public static EntityManager getEntityManager() {
    		EntityManager manager = threadLocal.get();
    		if (manager == null || !manager.isOpen()) {
    			manager = emf.createEntityManager();
    			manager.setFlushMode(FlushModeType.COMMIT);
    			threadLocal.set(manager);
    		}
    		return manager;
    	}

    #2
    Can you elaborate on why you think you need to do something with EntityManager at all? Have you looked over the docs for built-in transaction behavior in the JPA2DataSource?

    Comment


      #3
      Hi,

      we implement a new frontend (smartgwt) to already existing project. Its businesslogic is already writen and therefore we decided to use DMI.

      Some of the DMI fetch methods are complicated and do quite a lot of stuff.
      Some return POJO's and some return Hibernate entities. The project uses JPA2 with hibernate implementation.

      We use tomcat and would prefer not to deploy it on an application server. Server security is done using spring security.

      Now, we have an error in an application. When user change something. Closes and opens web browser then he reloads the data before the change. I tracked this error down and realized that the second browser could get an entity manager which has the object already loaded and did't refresh with database.

      I made changes the entity manager loading and set
      manager.setFlushMode(FlushModeType.COMMIT);
      so that every commit is immediatelly flushed into database.

      This doesn't solve my problem the other entitymanagers still have something in its cache. I believe that creating a new entity manager before procesing a client request would fix it. It is also a good idea to close entity manager when I am done with it.

      What do I do wrong? Or how can I achieve my goal?

      I probably need what you do in JPA2DataSource but I already have a business logic writen....

      Cheers,
      Zdary

      Comment


        #4
        Hi,

        In order to accommodate entityManager closing I created GenericFilterBean from SpringFramework.

        Is this a right approach?

        I'd like to introduce into my application JPA2DataSource for ListGrigs which edits one Table. How can I pass into the datasource my EntityManagerFactory?

        Code:
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        	HttpServletRequest request = (HttpServletRequest) req;
        	HttpServletResponse response = (HttpServletResponse) res;
        	HttpSession session = request.getSession(false);
        	if (session != null) {
        		SessionInformation info = sessionRegistry.getSessionInformation(session.getId());
        		if (info != null) {
        			if (info.isExpired()) {
        				doLogout(request, response);
        				if (invalidSessionHandler != null)
        					invalidSessionHandler.sessionInvalidated(request, response);
        				else {
        					response.getWriter().print("This session has been expired (possibly due to multiple concurrent " + "logins being attempted as the same user).");
        					response.flushBuffer();
        				}
        				return;
        			} else {
        				info.refreshLastRequest();
        			}
        		}
        	}
        	if (RPCManager.isRPC(request)) {
        		try {
        			chain.doFilter(request, response);
        		} finally {
        			// close entity manager and release database connection
        			EntityManagerHelper.closeEntityManager();
        		}
        	} else {
        		chain.doFilter(request, response);
        	}
        }

        Comment


          #5
          Why would you do any of this? JPA transactions ar automatically handled for JPA2DataSource in Power edition or above.

          Comment


            #6
            For example I need to authenticate user before I can use any datasource.
            Then I need to do data manipulation in business logic.

            Is there any docs on this topic?

            If I understand it I can define all datasources as JPA2DataSource and keep using DMI handling? How can I get the entity manager?

            We are going to buy Power edition anyway because of a messaging module.

            thanks,
            Zdary

            Comment


              #7
              If you want to use a JPA2DataSource within a filter, you can just use new DSRequest(..).execute(). You do not need to provide an EntityManager, it's automatic.

              Comment


                #8
                I still don't get it.

                My DAO contains NamedQueries or dynamically created queries. It;s responsible for filling paremeters and return data.

                How can I create the query without an entityManager?

                How can the rest of application work without the entityManager? for example, user click on recalculate data. This has nothing to do with a datasource and yet complex changes in a database will take place.

                Comment


                  #9
                  Could you be more specific in what you're asking..

                  If you asking how to use the JPA2DataSource to do a query at an arbitrary time, we've shown that, it does not require you to provide an EntityManager.

                  If you're asking about best practices for using Spring and JPA EntityManagers in general, this is not necessarily the right place to ask about this, and you should try other forums..

                  If you think the two are related in some way please be very, very specific about what problem you are trying to solve and why you think SmartGWT APIs are necessarily involved.

                  Comment


                    #10
                    Hi,

                    According to JPA spec you need to have just one entityManagerFactory which creates EntityManagers. If I create the factory by
                    Code:
                    EntityManagerFactory emf = Persistence.createEntityManagerFactory("xxx");
                    and you do the same inside the framework
                    Code:
                    jpa.emfProvider: com.isomorphic.jpa.EMFProviderLMT  
                    jpa.persistenceUnitName: xxx
                    How can L2cache be synchronized?

                    My second concern is about the datasource itself.
                    Imagine I have an entity Users which has a related object City which in turn has a related object Country.
                    I would like to show both columns county and city in a list grid.
                    How can I influence what I will see in a ListGrid filter?

                    Sometimes I'd like to see for city
                    Code:
                     select * from Cities
                    and in a different ListGrid
                    Code:
                     select distinct(user.city) from Users user
                    And if a user filters country I'd like to see only related cities in a city filter.

                    For these situations I have defined NamedQueries on JPA entities. How can I reuse these in JPA2DataSource? Or is there another approach to solve these situations?

                    I looked at your show case and I thing you have a bug there in a filter. Too many options. See a screenshot attached.
                    http://www.smartclient.com/smartgwtee/showcase/#jpaRelationManyToOneSimple

                    best regards,
                    Zdary
                    Attached Files

                    Comment


                      #11
                      Hi Zdary,

                      First some JPA stuff:
                      a) you can have as many EntityManagerFactory objects as you like - JPA specs and Hibernate implementation do not limit number of these objects. It is common practice to have a single EntityManagerFactory because it is expensive to create one.
                      b) EntityManagerFactory itself does not have connection to DB and does not maintain any cache - it is just mapping configuration. EntityManager has connection and loads entities into memory.
                      c) JPA specs require to flush before every commit. FlushModeType.COMMIT just informs provider to postpone flush till commit (it is not strict instruction - provider can choose to flush any time during transaction). Both modes (AUTO and COMMIT) flush changes before committing transaction.


                      Now on SmartGWT and your project:

                      Your problem (data are not saved) most probably lies in your code - either you forget to commit (and transaction is automatically rolled back) or exception is thrown while committing which you overlooked (again transaction is automatically rolled back) or you connection leaked and transaction is still in progress but you have no control over it.

                      All EntityManager objects must be closed after request is finished otherwise you will have connection leakage.

                      You should never rely on ThreadLocal in servlet environment - it is multi-threading by default. Moreover EntityManager objects are not thread safe.

                      Sharing EntityManagerFactory: there is no possibility to directly set your EntityManagerFactory for JPADataSource. You have two other possibilities:
                      a) configure "jpa.persistenceUnitName" property to your persistence unit name,
                      Use com.isomorphic.jpa.EMF static methods in your code to acquire EntityManager objects (JPADataSource works same way). For example:
                      Code:
                      EntityManager em = EMF.getEntityManager();
                      Object tx = EMF.getTransaction(em);
                      try {
                          // Do your stuff
                          EMF.commitTransaction(tx);
                      } catch (Exception ex) {
                          // Handle exception
                          EMF.rollbackTransaction(tx);
                      } finaly {
                          EMF.returnEntityManager(em);
                      }
                      b) Create you own implementation of com.isomorphic.jpa.EMFProviderInterface.
                      Set it via "jpa.emfProvider" property.
                      EMF instantiates your implementation on initialization (static) and uses same instance every time.
                      This way you have complete control over EntityManagerFactory and EntityManager objects creation and usage.

                      Avoiding lazy loading exception:
                      Read javadoc for com.isomorphic.jpa.JPADataSource (Transaction management) - there is explanation how JPADataSource handles transactions. You will have to implement something similar in your DMI data sources.

                      Best regards,
                      Alius

                      Comment


                        #12
                        Thank you very much for your support as well as for JPA stuff explanation.
                        I appreciate it.

                        Cheers,
                        Zdary

                        Comment

                        Working...
                        X