1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.orm.jdo;
  17. import javax.jdo.JDOException;
  18. import javax.jdo.PersistenceManager;
  19. import javax.jdo.PersistenceManagerFactory;
  20. import org.springframework.dao.DataAccessException;
  21. import org.springframework.transaction.support.TransactionSynchronizationManager;
  22. /**
  23. * Helper class that simplifies JDO data access code, and converts
  24. * JDOExceptions into JdoUsage/JdoSystemException, compatible to the
  25. * org.springframework.dao exception hierarchy.
  26. *
  27. * <p>The central method is "execute", supporting JDO code implementing
  28. * the JdoCallback interface. It provides JDO PersistenceManager handling
  29. * such that neither theJdoCallback implementation nor the calling code
  30. * needs to explicitly care about retrieving/closing PersistenceManagers,
  31. * or handling JDO lifecycle exceptions.
  32. *
  33. * <p>Typically used to implement data access or business logic services that
  34. * use JDO within their implementation but are JDO-agnostic in their interface.
  35. * The latter resp. code calling the latter only have to deal with business
  36. * objects, query objects, and org.springframework.dao exceptions.
  37. *
  38. * <p>Can be used within a service implementation via direct instantiation
  39. * with a PersistenceManagerFactory reference, or get prepared in an
  40. * application context and given to services as bean reference.
  41. * Note: The PersistenceManagerFactory should always be configured as bean in
  42. * the application context, in the first case given to the service directly,
  43. * in the second case to the prepared template.
  44. *
  45. * <p>This class can be considered a programmatic alternative to
  46. * JdoInterceptor. The major advantage is its straightforwardness, the
  47. * major disadvantage that no checked application exceptions can get thrown
  48. * from within data access code. Respective checks and the actual throwing of
  49. * such exceptions can often be deferred to after callback execution, though.
  50. *
  51. * <p>Note that even if JdoTransactionManager is used for transaction
  52. * demarcation in higher-level services, all those services above the data
  53. * access layer don't need need to be JDO-aware. Setting such a special
  54. * PlatformTransactionManager is a configuration issue, without introducing
  55. * code dependencies.
  56. *
  57. * <p>LocalPersistenceManagerFactoryBean is the preferred way of obtaining a
  58. * reference to a specific PersistenceManagerFactory, at least in a non-EJB
  59. * environment. Registering a PersistenceManagerFactory with JNDI is only
  60. * advisable when using a JCA Connector, i.e. when the application server
  61. * cares for initialization. Else, portability is rather limited: Manual
  62. * JNDI binding isn't supported by some application servers (e.g. Tomcat).
  63. *
  64. * @author Juergen Hoeller
  65. * @since 03.06.2003
  66. * @see JdoCallback
  67. * @see JdoTransactionManager
  68. */
  69. public class JdoTemplate extends JdoAccessor {
  70. private boolean allowCreate = true;
  71. /**
  72. * Create a new JdoTemplate instance.
  73. */
  74. public JdoTemplate() {
  75. }
  76. /**
  77. * Create a new JdoTemplate instance.
  78. * @param pmf PersistenceManagerFactory to create PersistenceManagers
  79. */
  80. public JdoTemplate(PersistenceManagerFactory pmf) {
  81. setPersistenceManagerFactory(pmf);
  82. afterPropertiesSet();
  83. }
  84. /**
  85. * Set if a new PersistenceManager should be created if no thread-bound found.
  86. * <p>JdoTemplate is aware of a respective PersistenceManager bound to the
  87. * current thread, for example when using JdoTransactionManager.
  88. * If allowCreate is true, a new PersistenceManager will be created if none
  89. * found. If false, an IllegalStateException will get thrown in this case.
  90. * @see PersistenceManagerFactoryUtils#getPersistenceManager
  91. */
  92. public void setAllowCreate(boolean allowCreate) {
  93. this.allowCreate = allowCreate;
  94. }
  95. /**
  96. * Return if a new Session should be created if no thread-bound found.
  97. */
  98. public boolean isAllowCreate() {
  99. return allowCreate;
  100. }
  101. /**
  102. * Execute the action specified by the given action object within a
  103. * PersistenceManager. Application exceptions thrown by the action object
  104. * get propagated to the caller (can only be unchecked). JDO exceptions
  105. * are transformed into appropriate DAO ones. Allows for returning a
  106. * result object, i.e. a domain object or a collection of domain objects.
  107. * <p>Note: Callback code is not supposed to handle transactions itself!
  108. * Use an appropriate transaction manager like JdoTransactionManager.
  109. * @param action action object that specifies the JDO action
  110. * @return a result object returned by the action, or null
  111. * @throws DataAccessException in case of JDO errors
  112. * @see JdoTransactionManager
  113. * @see org.springframework.dao
  114. * @see org.springframework.transaction
  115. */
  116. public Object execute(JdoCallback action) throws DataAccessException {
  117. PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(getPersistenceManagerFactory(), this.allowCreate);
  118. boolean existingTransaction = TransactionSynchronizationManager.hasResource(getPersistenceManagerFactory());
  119. try {
  120. Object result = action.doInJdo(pm);
  121. flushIfNecessary(pm, existingTransaction);
  122. return result;
  123. }
  124. catch (JDOException ex) {
  125. throw convertJdoAccessException(ex);
  126. }
  127. catch (RuntimeException ex) {
  128. // callback code threw application exception
  129. throw ex;
  130. }
  131. finally {
  132. PersistenceManagerFactoryUtils.closePersistenceManagerIfNecessary(pm, getPersistenceManagerFactory());
  133. }
  134. }
  135. }