Announcement Announcement Module
Collapse
No announcement yet.
JdoTemplate.find() fails because PM is closed Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JdoTemplate.find() fails because PM is closed

    Hi,

    I have implemented a simple DAO extending JdoDaoSupport. This DAO calls JdoTemplate.find to perform a query.

    This query fails (no objects found) because the PersistenceManager is closed before the JdoTemplate.find returns.

    In Kodo, the returned collection becomes unusable if the PersistenceManager is closed.

    My understanding is that the root cause is that a transaction is missing.

    I don't see why I must have a transaction for queries. I would appreciate any information about this.

    In order to make it work, I have anyway set a JdoTransactionManager and a TransactionProxyFactoryBean with PROPAGATION_REQUIRED set for my DAO methods.

    Unfortunately, it does not work better.

    Any help/comments are welcome,

    Best regards,

    Jean-François

  • #2
    NoSuchElementException

    I ran into this same problem trying to unit test a JDO DAO using kodo.

    If you try to iterate a collection returned by JdoTemplate.find(...) You can end up with a NoSuchElement exception:

    java.util.NoSuchElementException: The result list has been closed.
    at com.solarmetric.rop.AbstractResultList.assertOpen( AbstractResultList.java:99)
    at com.solarmetric.rop.ListResultList.size(ListResult List.java:87)
    ...

    Apparently, it doesn't want you to use any collection returned by a PersistenceManager once the PM is closed. Trouble is, if you're not already in a transaction, JdoTemplate.find(...) closes the PM in a finally block before it returns. The collection you get back is DOA.

    Comment


    • #3
      Hi,

      i also ran into the same problem in a out-of-transaction scenario, described a few posts earlier in this forum.

      First the JDO spec defines that a closed QueryResult is not iterateable anymore, thats whats happening when your transaction is no longer open when coming back from your JDOTemplate.find() call. JDOTemplate closes the PM only if its not inside a transaction (of course). So in normal operation mode with transaction interceptors and the correct demarcation, you dont have problems at all.

      I just wanted to write to the dev list regarding a possible change of JDOTemplate. For proper out-of-transaction usage (nontransactional read scenarios), JDOTemplate should give back a copy of the original QueryResult collection. This way JDOTemplate can close the PM and the caller can work with the result set later on. Returning the original collection is a no-go here.

      I hope someone from Spring-Dev is reading this, so that we can discuss this issue. At the moment its some kind of frustrating, because i cant use the same business classes (which use JDOTemplate and friends) out of J2EE/transaction context.

      Comment


      • #4
        Well, the problem is a bit more general, isn't it: JDO-persisted objects do not work outside of an active PersistenceManager *at all*. So it's not just about the Collection, it's also about each element of the collection. I'm afraid there's no other way than to explicitly detach collections/objects that are supposed to be usable outside of an active PersistenceManager.

        Note that Spring also allows you to define "pseudo-transactions": that is, demarcating transaction scopes with PROPAGATION_SUPPORTS instead of PROPAGATION_REQUIRED. This does not actually open resource transactions but nevertheless demarcates a resource scope: The same JDO PersistenceManager will be used for each such scope. So if you want to read non-transactionally, consider using PROPAGATION_SUPPORTS.

        Juergen

        Comment


        • #5
          No, with Kodo and auto-detachment, the objects inside the collection are perfectly valid. So this is not a show-stopper here. At least thats what i think, of course i could verifiy this by modifying JDOTemplate so that it returns a copied collection.

          Regarding manually detaching, the question here is when to do that. One must do that before leaving JDOTemplate.find() if i remember correctly. I dont think you can detach a closed QueryResult in user code that uses JDOTemplate. So i dont know how this can be done with find(), perhaps with an own JDOCallback while not using find().

          Regarding PROPAGATION_SUPPORTS, this is a problem for me, because i dont work with a transactional proxy in my commandline client but using classes that are normally accessed through tx-proxies. If i would have the full environment, i could easily use the normal demarcation here.

          Comment


          • #6
            I see... Interesting that auto-detachment applies to the persistent entities (and assumably their nested associations) but not the Collection results coming back from queries. Anyway, we might get around that by copying the Collection. It would be good if you could give this a try locally - let me know whether that approach works for you on Kodo!

            Juergen

            Comment


            • #7
              yeah its like i expected. i ran this code to check my assertions:

              Code:
              public class MyJDOTemplate extends JdoTemplate {
              
                  public MyJDOTemplate() {
                      super();
                  }
              
                  public MyJDOTemplate(PersistenceManagerFactory pmf) {
                      super(pmf);
                  }
              
                  public MyJDOTemplate(PersistenceManagerFactory pmf, boolean allowCreate) {
                      super(pmf, allowCreate);
                  }
              
                  /**
                   * Execute the action specified by the given action object within a
                   * PersistenceManager.
                   * @param action callback object that specifies the JDO action
                   * @param exposeNativePersistenceManager whether to expose the native
                   * JDO persistence manager to callback code
                   * @return a result object returned by the action, or null
                   * @throws org.springframework.dao.DataAccessException in case of JDO errors
                   */
                  public Object execute(JdoCallback action, boolean exposeNativePersistenceManager) throws DataAccessException {
                      PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(
                          getPersistenceManagerFactory(), isAllowCreate());
                      boolean existingTransaction =
                          TransactionSynchronizationManager.hasResource(getPersistenceManagerFactory());
                      try {
                          PersistenceManager pmToExpose = (exposeNativePersistenceManager ? pm : createPersistenceManagerProxy(pm));
                          Object result = action.doInJdo(pmToExpose);
                          flushIfNecessary(pm, existingTransaction);
                          if(result instanceof Collection) {
                              ArrayList al = new ArrayList();
                              al.addAll((Collection)result);
                              return al;
                          }
                          return result;
                      }
                      catch (JDOException ex) {
                          throw convertJdoAccessException(ex);
                      }
                      catch (RuntimeException ex) {
                          // callback code threw application exception
                          throw ex;
                      }
                      finally {
                          PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory());
                      }
                  }
              }
              I have overriden the execute() but i tested with the find() which calls execute() behind the scenes of course. We cant do the collection stuff in find because of the callback the PM is allready closed there. But i ve done this in 2 minutes or something, its just a proof of concept.

              After all i am able to workt with the collection, even if the PM is closed. So do you see way to integrate that into JDOTemplate itself? IMO JdoTemplate knows when it runs in non-tx mode, so we can create a new collection before returning in this scenario cant we?

              Comment


              • #8
                For a start, I've introduced a protected "postProcessResult(Object result, PersistenceManager pm, boolean existingTransaction)" template method, called by JdoTemplate's execute methods. I'm inclined to leave the default implementation empty (always returning the passed-in object as-is), though, to avoid potential side effects - as we don't know how different JDO providers behave here yet.

                This hook will be part of Spring 1.2.6; I would recommend to create your own custom JdoTemplate subclass for the time being. I'll revisit this for Spring 1.3, after we've had a bit more time to research this for various JDO providers. We might add some default auto-detachment there then.

                BTW, instead of creating a plain ArrayList copy, wouldn't it also be feasible to use "PersistenceManager.detachCopyAll(Collection)" , respectively "JdoDialect.detachCopyAll(Collection)"? That should detach both the Collection and the contained objects, shouldn't it.

                Juergen

                Comment


                • #9
                  yeah we should definitely use spring controlled auto-detachment because otherwise we will definitely run into problems with various providers. My current setting with Kodo (detachOnClose) is definitely non-standard and i dont know if this feature is available in any other product.

                  But with your suggestion, there shouldnt be a problem with different providers in non-tx mode. In fact, this will be a nice feature add-on for JDOTemplate. I would appreciate to see your approach in implementing this in JDOTemplate before it gets in the release. Perhaps i can give some more feeback on this. At least i am the perfect test-user

                  Looking forward to see the enhanced JDOTemplate.

                  Comment


                  • #10
                    Originally posted by Juergen Hoeller
                    This hook will be part of Spring 1.2.6; I would recommend to create your own custom JdoTemplate subclass for the time being. I'll revisit this for Spring 1.3, after we've had a bit more time to research this for various JDO providers. We might add some default auto-detachment there then.

                    BTW, instead of creating a plain ArrayList copy, wouldn't it also be feasible to use "PersistenceManager.detachCopyAll(Collection)" , respectively "JdoDialect.detachCopyAll(Collection)"? That should detach both the Collection and the contained objects, shouldn't it.

                    Juergen
                    Hi Juergen,

                    Now I extend JdoTemplte class and override postProcessResult() method. It seems the only thing I can do is to return a new copied collection? I tried to use KodoPersistentManager (kodo 3.4) to detachAll the collection but it will still be closed.

                    So actually although I override that method, I can only return a new copy of resultlist?

                    Thanks

                    Comment

                    Working...
                    X