A form handler that can manipulate repository items should ensure that all operations that occur in a handler method call happen in a single transaction. If all the operations in a method call do not occur in the same transaction, there is the risk that if something goes wrong in the middle of the operation, incomplete data is committed to the repository. Committing all the operations at once ensures that a repository or database transaction is either completed successfully, or not completed at all, and any partially committed data is rolled back.
The RepositoryFormHandler and TransactionalRepositoryFormHandler classes ensure atomic transactions in this way. If you subclass either class without overriding the handler methods, your subclass handles transactions properly. If you override any handler methods, or add new handler methods, you must make sure that these methods handle transactions properly.
To create a form handler that works with repository items while a transaction is in progress:
Create a form handler that is a subclass of either
RepositoryFormHandlerorTransactionalRepositoryFormHandler. See Using RepositoryFormHandler or TransactionalRepositoryFormHandler.Create methods on your new form handler that are transaction-aware. See Creating Methods that Support Transactions.
Note: Keep in mind that RepositoryFormHandler and TransactionalRepositoryFormHandler are useful for manipulating repository items specifically. If you’d rather work with the JDBC directly in a form handler that supports transactions, use the atg.droplet.TransactionFormHandler.
Using RepositoryFormHandler or TransactionalRepositoryFormHandler
You need to decide which form handler, TransactionalRepositoryFormHandler or RepositoryFormHandler, you want to subclass. The source code for both form handlers is provided here: <ATG9dir>/DAS/src/Java/atg/repository/servlet. You can also navigate to API documentation for both classes in ATG API Reference.
The atg.repository.servlet.RepositoryFormHandler is a base form handler that provides tools for creating, modifying, and deleting items stored in an SQL repository. The only direct instance of this class provided in the ATG Adaptive Scenario Engine is /atg/demo/QuincyFunds/FormHandlers/EmailRepositoryFormHandler. Learn more about this form handler by reading the Using Repository Form Handlers chapter of the ATG Page Developer’s Guide.
The atg.repository.servlet.TransactionalRepositoryFormHandler, a subclass of the RepositoryFormhandler, provides enhanced transaction support by broadening the scope of the transaction. This class also defines a few additional properties that are useful for transaction monitoring. ATG Adaptive Scenario Engine does not include any instances of this class.
Both form handlers create a transaction if one is not already in progress and provide the status of all operations performed by the form handler while the transaction is in place. The main difference between the form handlers is the lifespan of the transaction.
In the RepositoryFormhandler, the transaction is governed entirely by the submit handler method, meaning the transaction starts when a submit handler method is invoked and ends when it completes execution. Transaction status is reported for the data validation and the data commit operations.
Transactions in the TransactionalRepositoryFormHandler begin when the beforeSet method is invoked and end with the afterSet method. Because a transaction status is generated for all operations that occur during its execution, a status is recorded for each the following operations:
beforeSetmethod executionprocessing of all other tags in the JSP (tags that implement submit operations have the lowest priority on the page)
submit handler method data validation
submit handler method data commit
afterSetmethod execution
So, choose your superclass form handler class based on the actions that you want included in a transaction.
Note: A transaction is started and ended by a form handler only when there are no other active transactions. If a transaction is in progress, the form handler returns a status for each operation it attempts and permits the transaction to continue after the form handler itself finishes processing.
Creating Methods that Support Transactions
After you create your subclass, make sure that the methods you specify for it can correspond with the Transaction Manager. There are two ways to do this:
Base your new handler methods on the existing
handleUpdatecode so that you can re-use the transaction code in it and then modify the rest accordingly.Expand the existing handler methods by inserting code before or after their execution in the
preXorpostXmethods respectively.
New Methods Based on handleUpdate Source Code
The code provided here implements the handleUpdate method. Create your own handler methods by making changes to this code sample and inserting it into your subclassed form handler:
public boolean handleUpdate(DynamoHttpServletRequest pRequest,
DynamoHttpServletResponse pResponse)
throws ServletException, IOException
{
TransactionDemarcation td = getTransactionDemarcation();
TransactionManager tm = getTransactionManager();
try {
if (tm != null) td.begin(tm, td.REQUIRED);
int status = checkFormError(getUpdateErrorURL(), pRequest, pResponse);
if (status != STATUS_SUCCESS) return status == STATUS_ERROR_STAY;
// update the repository item
preUpdateItem(pRequest, pResponse);
if (!getFormError())
updateItem(pRequest, pResponse);
postUpdateItem(pRequest, pResponse);
// try to redirect on errors
if ((status = checkFormError(getUpdateErrorURL(), pRequest, pResponse))
!= STATUS_SUCCESS)
return status == STATUS_ERROR_STAY;
// try to redirect on success
return checkFormSuccess(getUpdateSuccessURL(), pRequest, pResponse);
}
catch (TransactionDemarcationException e) {
throw new ServletException(e);
}
finally {
try { if (tm != null) td.end(); }
catch (TransactionDemarcationException e) { }
}
}Extending Existing Methods
The three existing submit handler methods (handleCreate, handleUpdate, and handleDelete) each come with a pair of empty pre and post methods to which you can add custom code.
It is likely that you use either the preX or the postX method for a given existing handler method although it is possible for you to customize both. For example, consider a subclass of TransactionalRepositoryFormHandler where preUpdate and postUpdate are used:
The form is rendered, which causes
getXmethod to display current values for properties used in the form.The user fills in the form and submits it.
The form handler’s
beforeSetmethod is invoked. If a transaction is not currently in progress, theTransactionalRepositoryFormHandlercomponent creates a one.If tag converters are used, they are applied to the specified content. Any form exceptions that occur now or at any point during the form handler execution are saved to the form handler’s
formExceptionproperty.The
setXmethod is called, followed by the form handler’shandleUpdatemethod. Severe form exceptions might cause form processing to stop and the transaction to rollback, before redirecting users to a different page.The
preUpdateItemmethod is invoked. ThepreXmethod for thehandleUpdatemethod ispreUpdateItem. Serious errors generated from this operation might also prompt the transaction to rollback.The
updateItemmethod, which is thehandleUpdatemethod responsible for processing the content and updating the database, is invoked. Again, this is another operation that can cause a transaction to rollback when serious errors are detected. At this point, the changes made by the actions associated with the transaction are kept private, meaning that they are only visible within the transaction itself.The
postUpdateItemmethod is invoked. Again, the transaction is rolled back if serious errors are detected.The
afterSetmethod is invoked. If the transaction was started by thebeforeSetmethod, the transaction concludes and the content it saved to the database is publicly visible.
You should use the preX method when you want to expand the constraints for data validation. For example, you might want to check if the user-entered zip code and country correspond to each other. The countries that use zip codes require them to be a certain length. The preX method can verify that a zip code uses the appropriate format for the country, before saving the zip code and country values to the database. Any discrepancies produce a form exception and roll back the transaction.
Alternatively, the postX method is useful when you want to verify user entered-data after that data has been converted by tag converters. For example, a form handler that saves credit card information might use a postX method to handle authorization. After that credit card number has been formatted correctly and all related information is updated in the database, the postX method executes. If the authorization fails, the transaction is rolled back, the original data refreshed, a form error exception is thrown, and the user is redirected to a page where the use can re-enter credit card information.

