Preventing rollback of a specific database transaction in Java after throwing a UserException

6
I'm catching exceptions in Java, in these error handlers I'm calling a method in a helper class to write a log object. In some cases I'd like to throw a UserException as well. Throwing this exception prevents my Log object from being created though, as the commit will be rollbacked. Below is my code, how would I make sure everything else receives a rollback but the Log object gets written? public class LogCreator { public LogCreator(Account currentAccount, IContext context) { this.context = context; this.currentAccount = currentAccount; } public void writeLog(String logMessage, Exception e, boolean throwUserException, String logNodeName) throws CoreException, UserException { String fullErrorString = logMessage + ": " + e.toString() + ": " + e.getMessage(); Core.getLogNode(logNodeName).error(fullErrorString); Log log = Log.create(context); log.setLogMessage(fullErrorString); log.setLog_Account(currentAccount); Core.commit(context, log.getMendixObject()); if (throwUserException) { throw new UserException(ExceptionCategory.Custom, fullErrorString); } } private IContext context; private Account currentAccount; }
asked
2 answers
5

This a good solution to prevent the log object from being rollbacked. Please note, however, that when a exception would occur in the creation of the log object, no rollback mechanism is used now. To facilitate this, the startTransaction(), endTransaction() and rollbackTransaction() methods of IContext can be used.

The method startTransaction() starts a new transaction, or when the context is already in a transaction, creates a savepoint.

The endTransaction() method commits the current transaction if no savepoints are present, otherwise a savepoint is removed.

Finally, rollbackTransaction() rolls back the entire current transaction if no savepoints are present, otherwise a rollback to the last savepoint is performed.

In your example, this can be applied as follows:

public void writeLog(String logMessage, Exception e, boolean throwUserException, String logNodeName) throws CoreException, UserException
{
    String fullErrorString = logMessage + ": " + e.toString() + ": " + e.getMessage();
    Core.getLogNode(logNodeName).error(fullErrorString);
    IContext newContext = new Context((Session)this.context.getSession());
    newContext.startTransaction();
    try
    {
      Log log = Log.create(newContext);
      log.setLogMessage(fullErrorString);
      log.setLog_Account(currentAccount);
      Core.commit(newContext, log.getMendixObject());
    }
    catch(CoreException e)
    {
       newContext.rollbackTransaction();
       throw new MendixRuntimeException(e);
    }
    newContext.commitTransaction();

    if (throwUserException)
    {
        throw new UserException(ExceptionCategory.Custom, fullErrorString);
    }
}
answered
3

Looks like I found out. I'm using a new Context to commit the Log object. New writeLog method:

public void writeLog(String logMessage, Exception e, boolean throwUserException, String logNodeName) throws CoreException, UserException
{
    String fullErrorString = logMessage + ": " + e.toString() + ": " + e.getMessage();
    Core.getLogNode(logNodeName).error(fullErrorString);
    IContext newContext = new Context((Session)this.context.getSession());
    Log log = Log.create(newContext);
    log.setLogMessage(fullErrorString);
    log.setLog_Account(currentAccount);
    Core.commit(newContext, log.getMendixObject());
    if (throwUserException)
    {
        throw new UserException(ExceptionCategory.Custom, fullErrorString);
    }
}
answered