\r
@Transactional(TransactionMode.DISABLED) // NOTE: we are handling transaction by ourself in this class, thus we prevent unitils from creating transactions\r
public abstract class CdmTransactionalIntegrationTest extends CdmIntegrationTest {\r
- protected static final Logger logger = Logger.getLogger(CdmTransactionalIntegrationTest.class);\r
-\r
- /**\r
- * The transaction manager to use\r
- */\r
- @SpringBeanByType\r
- PlatformTransactionManager transactionManager;\r
-\r
- /**\r
- * Should we roll back by default?\r
- */\r
- private boolean defaultRollback = true;\r
-\r
- /**\r
- * Should we commit the current transaction?\r
- */\r
- private boolean complete = false;\r
-\r
- /**\r
- * Number of transactions started\r
- */\r
- private int transactionsStarted = 0;\r
-\r
- /**\r
- * Transaction definition used by this test class: by default, a plain\r
- * DefaultTransactionDefinition. Subclasses can change this to cause\r
- * different behavior.\r
- */\r
- protected TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();\r
-\r
- /**\r
- * TransactionStatus for this test. Typical subclasses won't need to use it.\r
- */\r
- protected TransactionStatus transactionStatus;\r
-\r
- /**\r
- * Get the <em>default rollback</em> flag for this test.\r
- *\r
- * @see #setDefaultRollback(boolean)\r
- * @return The <em>default rollback</em> flag.\r
- */\r
- protected boolean isDefaultRollback() {\r
- return this.defaultRollback;\r
- }\r
-\r
- /**\r
- * Subclasses can set this value in their constructor to change the default,\r
- * which is always to roll the transaction back.\r
- */\r
- public void setDefaultRollback(final boolean defaultRollback) {\r
- this.defaultRollback = defaultRollback;\r
- }\r
-\r
- /**\r
- * <p>\r
- * Determines whether or not to rollback transactions for the current test.\r
- * </p>\r
- * <p>\r
- * The default implementation delegates to {@link #isDefaultRollback()}.\r
- * Subclasses can override as necessary.\r
- * </p>\r
- *\r
- * @return The <em>rollback</em> flag for the current test.\r
- */\r
- protected boolean isRollback() {\r
- return isDefaultRollback();\r
- }\r
-\r
- /**\r
- * Call this method in an overridden {@link #runBare()} method to prevent\r
- * transactional execution.\r
- */\r
- protected void preventTransaction() {\r
- this.transactionDefinition = null;\r
- }\r
-\r
- /**\r
- * Call this method in an overridden {@link #runBare()} method to override\r
- * the transaction attributes that will be used, so that {@link #setUp()}\r
- * and {@link #tearDown()} behavior is modified.\r
- *\r
- * @param customDefinition the custom transaction definition\r
- */\r
- protected void setTransactionDefinition(final TransactionDefinition customDefinition) {\r
- this.transactionDefinition = customDefinition;\r
- }\r
-\r
- /**\r
- * This implementation creates a transaction before test execution.\r
- * <p>\r
- * Override {@link #onSetUpBeforeTransaction()} and/or\r
- * {@link #onSetUpInTransaction()} to add custom set-up behavior for\r
- * transactional execution. Alternatively, override this method for general\r
- * set-up behavior, calling <code>super.onSetUp()</code> as part of your\r
- * method implementation.\r
- *\r
- * @throws Exception simply let any exception propagate\r
- * @see #onTearDown()\r
- */\r
- @Before\r
- public void onSetUp() throws Exception {\r
-\r
- this.complete = !this.isRollback();\r
-\r
- if (this.transactionManager == null) {\r
- logger.info("No transaction manager set: test will NOT run within a transaction");\r
- }\r
- else if (this.transactionDefinition == null) {\r
- logger.info("No transaction definition set: test will NOT run within a transaction");\r
- }\r
- else {\r
- onSetUpBeforeTransaction();\r
- startNewTransaction();\r
- try {\r
- onSetUpInTransaction();\r
- }\r
- catch (final Exception ex) {\r
- endTransaction();\r
- throw ex;\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Subclasses can override this method to perform any setup operations, such\r
- * as populating a database table, <i>before</i> the transaction created by\r
- * this class. Only invoked if there <i>is</i> a transaction: that is, if\r
- * {@link #preventTransaction()} has not been invoked in an overridden\r
- * {@link #runTest()} method.\r
- *\r
- * @throws Exception simply let any exception propagate\r
- */\r
- protected void onSetUpBeforeTransaction() throws Exception {\r
-\r
- }\r
-\r
- /**\r
- * Subclasses can override this method to perform any setup operations, such\r
- * as populating a database table, <i>within</i> the transaction created by\r
- * this class.\r
- * <p>\r
- * <b>NB:</b> Not called if there is no transaction management, due to no\r
- * transaction manager being provided in the context.\r
- * <p>\r
- * If any {@link Throwable} is thrown, the transaction that has been started\r
- * prior to the execution of this method will be\r
- * {@link #endTransaction() ended} (or rather an attempt will be made to\r
- * {@link #endTransaction() end it gracefully}); The offending\r
- * {@link Throwable} will then be rethrown.\r
- *\r
- * @throws Exception simply let any exception propagate\r
- */\r
- protected void onSetUpInTransaction() throws Exception {\r
-\r
- }\r
-\r
- /**\r
- * This implementation ends the transaction after test execution.\r
- * <p>\r
- * Override {@link #onTearDownInTransaction()} and/or\r
- * {@link #onTearDownAfterTransaction()} to add custom tear-down behavior\r
- * for transactional execution. Alternatively, override this method for\r
- * general tear-down behavior, calling <code>super.onTearDown()</code> as\r
- * part of your method implementation.\r
- * <p>\r
- * Note that {@link #onTearDownInTransaction()} will only be called if a\r
- * transaction is still active at the time of the test shutdown. In\r
- * particular, it will <i>not</i> be called if the transaction has been\r
- * completed with an explicit {@link #endTransaction()} call before.\r
- *\r
- * @throws Exception simply let any exception propagate\r
- * @see #onSetUp()\r
- */\r
- @After\r
- public void onTearDown() throws Exception {\r
-\r
- // Call onTearDownInTransaction and end transaction if the transaction\r
- // is still active.\r
- if (this.transactionStatus != null && !this.transactionStatus.isCompleted()) {\r
- try {\r
- onTearDownInTransaction();\r
- }\r
- finally {\r
- endTransaction();\r
- }\r
- }\r
- // Call onTearDownAfterTransaction if there was at least one\r
- // transaction, even if it has been completed early through an\r
- // endTransaction() call.\r
- if (this.transactionsStarted > 0) {\r
- onTearDownAfterTransaction();\r
- }\r
- }\r
-\r
- /**\r
- * Subclasses can override this method to run invariant tests here. The\r
- * transaction is <i>still active</i> at this point, so any changes made in\r
- * the transaction will still be visible. However, there is no need to clean\r
- * up the database, as a rollback will follow automatically.\r
- * <p>\r
- * <b>NB:</b> Not called if there is no actual transaction, for example due\r
- * to no transaction manager being provided in the application context.\r
- *\r
- * @throws Exception simply let any exception propagate\r
- */\r
- protected void onTearDownInTransaction() throws Exception {\r
-\r
- }\r
-\r
- /**\r
- * Subclasses can override this method to perform cleanup after a\r
- * transaction here. At this point, the transaction is <i>not active anymore</i>.\r
- *\r
- * @throws Exception simply let any exception propagate\r
- */\r
- protected void onTearDownAfterTransaction() throws Exception {\r
-\r
- }\r
-\r
- /**\r
- * Cause the transaction to commit for this test method, even if the test\r
- * method is configured to {@link #isRollback() rollback}.\r
- *\r
- * @throws IllegalStateException if the operation cannot be set to complete\r
- * as no transaction manager was provided\r
- */\r
- protected void setComplete() {\r
-\r
- if (this.transactionManager == null) {\r
- throw new IllegalStateException("No transaction manager set");\r
- }\r
- this.complete = true;\r
- }\r
-\r
- /**\r
- * Immediately force a commit or rollback of the transaction, according to\r
- * the <code>complete</code> and {@link #isRollback() rollback} flags.\r
- * <p>\r
- * Can be used to explicitly let the transaction end early, for example to\r
- * check whether lazy associations of persistent objects work outside of a\r
- * transaction (that is, have been initialized properly).\r
- *\r
- * @see #setComplete()\r
- */\r
- protected void endTransaction() {\r
-\r
- final boolean commit = this.complete || !isRollback();\r
-\r
- if (this.transactionStatus != null) {\r
- try {\r
- if (commit) {\r
- this.transactionManager.commit(this.transactionStatus);\r
- logger.debug("Committed transaction after execution of test");\r
- }\r
- else {\r
- this.transactionManager.rollback(this.transactionStatus);\r
- logger.debug("Rolled back transaction after execution of test.");\r
- }\r
- }\r
- finally {\r
- this.transactionStatus = null;\r
- }\r
- }\r
- }\r
-\r
- protected void rollback() {\r
-\r
- if (this.transactionStatus != null) {\r
- try {\r
- this.transactionManager.rollback(this.transactionStatus);\r
- logger.debug("Rolled back transaction after execution of test.");\r
- }\r
- finally {\r
- this.transactionStatus = null;\r
- }\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Start a new transaction. Only call this method if\r
- * {@link #endTransaction()} has been called. {@link #setComplete()} can be\r
- * used again in the new transaction. The fate of the new transaction, by\r
- * default, will be the usual rollback.\r
- *\r
- * @throws TransactionException if starting the transaction failed\r
- */\r
- protected void startNewTransaction() throws TransactionException {\r
-\r
- if (this.transactionStatus != null) {\r
- throw new IllegalStateException("Cannot start new transaction without ending existing transaction: "\r
- + "Invoke endTransaction() before startNewTransaction()");\r
- }\r
- if (this.transactionManager == null) {\r
- throw new IllegalStateException("No transaction manager set");\r
- }\r
-\r
- this.transactionStatus = this.transactionManager.getTransaction(this.transactionDefinition);\r
- ++this.transactionsStarted;\r
- this.complete = !this.isRollback();\r
-\r
- if (logger.isDebugEnabled()) {\r
- logger.debug("Began transaction (" + this.transactionsStarted + "): transaction manager ["\r
- + this.transactionManager + "]; rollback [" + this.isRollback() + "].");\r
- }\r
- }\r
-\r
-\r
- /**\r
- * @param tableNames\r
- */\r
- protected void commitAndStartNewTransaction(final String[] tableNames) {\r
- setComplete();\r
- endTransaction();\r
-// printDataSet(System.out, tableNames);\r
- startNewTransaction();\r
- }\r
+ protected static final Logger logger = Logger.getLogger(CdmTransactionalIntegrationTest.class);\r
+\r
+ /**\r
+ * The transaction manager to use\r
+ */\r
+ @SpringBeanByType\r
+ PlatformTransactionManager transactionManager;\r
+\r
+ /**\r
+ * Should we roll back by default?\r
+ */\r
+ private boolean defaultRollback = true;\r
+\r
+ /**\r
+ * Should we commit the current transaction?\r
+ */\r
+ private boolean complete = false;\r
+\r
+ /**\r
+ * Number of transactions started\r
+ */\r
+ private int transactionsStarted = 0;\r
+\r
+ /**\r
+ * Transaction definition used by this test class: by default, a plain\r
+ * DefaultTransactionDefinition. Subclasses can change this to cause\r
+ * different behavior.\r
+ */\r
+ protected TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();\r
+\r
+ /**\r
+ * TransactionStatus for this test. Typical subclasses won't need to use it.\r
+ */\r
+ protected TransactionStatus transactionStatus;\r
+\r
+ /**\r
+ * Get the <em>default rollback</em> flag for this test.\r
+ *\r
+ * @see #setDefaultRollback(boolean)\r
+ * @return The <em>default rollback</em> flag.\r
+ */\r
+ protected boolean isDefaultRollback() {\r
+ return this.defaultRollback;\r
+ }\r
+\r
+ /**\r
+ * Subclasses can set this value in their constructor to change the default,\r
+ * which is always to roll the transaction back.\r
+ */\r
+ public void setDefaultRollback(final boolean defaultRollback) {\r
+ this.defaultRollback = defaultRollback;\r
+ }\r
+\r
+ /**\r
+ * <p>\r
+ * Determines whether or not to rollback transactions for the current test.\r
+ * </p>\r
+ * <p>\r
+ * The default implementation delegates to {@link #isDefaultRollback()}.\r
+ * Subclasses can override as necessary.\r
+ * </p>\r
+ *\r
+ * @return The <em>rollback</em> flag for the current test.\r
+ */\r
+ protected boolean isRollback() {\r
+ return isDefaultRollback();\r
+ }\r
+\r
+ /**\r
+ * Call this method in an overridden {@link #runBare()} method to prevent\r
+ * transactional execution.\r
+ */\r
+ protected void preventTransaction() {\r
+ this.transactionDefinition = null;\r
+ }\r
+\r
+ /**\r
+ * Call this method in an overridden {@link #runBare()} method to override\r
+ * the transaction attributes that will be used, so that {@link #setUp()}\r
+ * and {@link #tearDown()} behavior is modified.\r
+ *\r
+ * @param customDefinition the custom transaction definition\r
+ */\r
+ protected void setTransactionDefinition(final TransactionDefinition customDefinition) {\r
+ this.transactionDefinition = customDefinition;\r
+ }\r
+\r
+ /**\r
+ * This implementation creates a transaction before test execution.\r
+ * <p>\r
+ * Override {@link #onSetUpBeforeTransaction()} and/or\r
+ * {@link #onSetUpInTransaction()} to add custom set-up behavior for\r
+ * transactional execution. Alternatively, override this method for general\r
+ * set-up behavior, calling <code>super.onSetUp()</code> as part of your\r
+ * method implementation.\r
+ *\r
+ * @throws Exception simply let any exception propagate\r
+ * @see #onTearDown()\r
+ */\r
+ @Before\r
+ public void onSetUp() throws Exception {\r
+\r
+ this.complete = !this.isRollback();\r
+\r
+ if (this.transactionManager == null) {\r
+ logger.info("No transaction manager set: test will NOT run within a transaction");\r
+ }\r
+ else if (this.transactionDefinition == null) {\r
+ logger.info("No transaction definition set: test will NOT run within a transaction");\r
+ }\r
+ else {\r
+ onSetUpBeforeTransaction();\r
+ startNewTransaction();\r
+ try {\r
+ onSetUpInTransaction();\r
+ }\r
+ catch (final Exception ex) {\r
+ endTransaction();\r
+ throw ex;\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Subclasses can override this method to perform any setup operations, such\r
+ * as populating a database table, <i>before</i> the transaction created by\r
+ * this class. Only invoked if there <i>is</i> a transaction: that is, if\r
+ * {@link #preventTransaction()} has not been invoked in an overridden\r
+ * {@link #runTest()} method.\r
+ *\r
+ * @throws Exception simply let any exception propagate\r
+ */\r
+ protected void onSetUpBeforeTransaction() throws Exception {\r
+\r
+ }\r
+\r
+ /**\r
+ * Subclasses can override this method to perform any setup operations, such\r
+ * as populating a database table, <i>within</i> the transaction created by\r
+ * this class.\r
+ * <p>\r
+ * <b>NB:</b> Not called if there is no transaction management, due to no\r
+ * transaction manager being provided in the context.\r
+ * <p>\r
+ * If any {@link Throwable} is thrown, the transaction that has been started\r
+ * prior to the execution of this method will be\r
+ * {@link #endTransaction() ended} (or rather an attempt will be made to\r
+ * {@link #endTransaction() end it gracefully}); The offending\r
+ * {@link Throwable} will then be rethrown.\r
+ *\r
+ * @throws Exception simply let any exception propagate\r
+ */\r
+ protected void onSetUpInTransaction() throws Exception {\r
+\r
+ }\r
+\r
+ /**\r
+ * This implementation ends the transaction after test execution.\r
+ * <p>\r
+ * Override {@link #onTearDownInTransaction()} and/or\r
+ * {@link #onTearDownAfterTransaction()} to add custom tear-down behavior\r
+ * for transactional execution. Alternatively, override this method for\r
+ * general tear-down behavior, calling <code>super.onTearDown()</code> as\r
+ * part of your method implementation.\r
+ * <p>\r
+ * Note that {@link #onTearDownInTransaction()} will only be called if a\r
+ * transaction is still active at the time of the test shutdown. In\r
+ * particular, it will <i>not</i> be called if the transaction has been\r
+ * completed with an explicit {@link #endTransaction()} call before.\r
+ *\r
+ * @throws Exception simply let any exception propagate\r
+ * @see #onSetUp()\r
+ */\r
+ @After\r
+ public void onTearDown() throws Exception {\r
+\r
+ // Call onTearDownInTransaction and end transaction if the transaction\r
+ // is still active.\r
+ if (this.transactionStatus != null && !this.transactionStatus.isCompleted()) {\r
+ try {\r
+ onTearDownInTransaction();\r
+ }\r
+ finally {\r
+ endTransaction();\r
+ }\r
+ }\r
+ // Call onTearDownAfterTransaction if there was at least one\r
+ // transaction, even if it has been completed early through an\r
+ // endTransaction() call.\r
+ if (this.transactionsStarted > 0) {\r
+ onTearDownAfterTransaction();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Subclasses can override this method to run invariant tests here. The\r
+ * transaction is <i>still active</i> at this point, so any changes made in\r
+ * the transaction will still be visible. However, there is no need to clean\r
+ * up the database, as a rollback will follow automatically.\r
+ * <p>\r
+ * <b>NB:</b> Not called if there is no actual transaction, for example due\r
+ * to no transaction manager being provided in the application context.\r
+ *\r
+ * @throws Exception simply let any exception propagate\r
+ */\r
+ protected void onTearDownInTransaction() throws Exception {\r
+\r
+ }\r
+\r
+ /**\r
+ * Subclasses can override this method to perform cleanup after a\r
+ * transaction here. At this point, the transaction is <i>not active anymore</i>.\r
+ *\r
+ * @throws Exception simply let any exception propagate\r
+ */\r
+ protected void onTearDownAfterTransaction() throws Exception {\r
+\r
+ }\r
+\r
+ /**\r
+ * Cause the transaction to commit for this test method, even if the test\r
+ * method is configured to {@link #isRollback() rollback}.\r
+ *\r
+ * @throws IllegalStateException if the operation cannot be set to complete\r
+ * as no transaction manager was provided\r
+ */\r
+ protected void setComplete() {\r
+\r
+ if (this.transactionManager == null) {\r
+ throw new IllegalStateException("No transaction manager set");\r
+ }\r
+ this.complete = true;\r
+ }\r
+\r
+ /**\r
+ * Immediately force a commit or rollback of the transaction, according to\r
+ * the <code>complete</code> and {@link #isRollback() rollback} flags.\r
+ * <p>\r
+ * Can be used to explicitly let the transaction end early, for example to\r
+ * check whether lazy associations of persistent objects work outside of a\r
+ * transaction (that is, have been initialized properly).\r
+ *\r
+ * @see #setComplete()\r
+ */\r
+ protected void endTransaction() {\r
+\r
+ final boolean commit = this.complete || !isRollback();\r
+\r
+ if (this.transactionStatus != null) {\r
+ try {\r
+ if (commit) {\r
+ this.transactionManager.commit(this.transactionStatus);\r
+ logger.debug("Committed transaction after execution of test");\r
+ }\r
+ else {\r
+ this.transactionManager.rollback(this.transactionStatus);\r
+ logger.debug("Rolled back transaction after execution of test.");\r
+ }\r
+ }\r
+ finally {\r
+ this.transactionStatus = null;\r
+ }\r
+ }\r
+ }\r
+\r
+ protected void rollback() {\r
+\r
+ if (this.transactionStatus != null) {\r
+ try {\r
+ this.transactionManager.rollback(this.transactionStatus);\r
+ logger.debug("Rolled back transaction after execution of test.");\r
+ }\r
+ finally {\r
+ this.transactionStatus = null;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Start a new transaction. Only call this method if\r
+ * {@link #endTransaction()} has been called. {@link #setComplete()} can be\r
+ * used again in the new transaction. The fate of the new transaction, by\r
+ * default, will be the usual rollback.\r
+ *\r
+ * @throws TransactionException if starting the transaction failed\r
+ */\r
+ protected void startNewTransaction() throws TransactionException {\r
+\r
+ if (this.transactionStatus != null) {\r
+ throw new IllegalStateException("Cannot start new transaction without ending existing transaction: "\r
+ + "Invoke endTransaction() before startNewTransaction()");\r
+ }\r
+ if (this.transactionManager == null) {\r
+ throw new IllegalStateException("No transaction manager set");\r
+ }\r
+\r
+ this.transactionStatus = this.transactionManager.getTransaction(this.transactionDefinition);\r
+ ++this.transactionsStarted;\r
+ this.complete = !this.isRollback();\r
+\r
+ if (logger.isDebugEnabled()) {\r
+ logger.debug("Began transaction (" + this.transactionsStarted + "): transaction manager ["\r
+ + this.transactionManager + "]; rollback [" + this.isRollback() + "].");\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * @param tableNames the tables supplied by this array will be <b>printed after</b> the transaction has committed\r
+ * and ended <b>only if the logging level is set to debug</b>, e.g.:\r
+ * <pre>\r
+ * log4j.logger.eu.etaxonomy.cdm.test.integration=DEBUG\r
+ * </pre>\r
+ */\r
+ protected void commitAndStartNewTransaction(final String[] tableNames) {\r
+ setComplete();\r
+ endTransaction();\r
+ if(logger.isDebugEnabled()){\r
+ printDataSet(System.out, tableNames);\r
+ }\r
+ startNewTransaction();\r
+ }\r
\r
}\r