private Object runInTx(Task task, Object... input) {
   HibernateCallback action = new RunInHibernate(task, input);
   TransactionTemplate txTemplate = new TransactionTemplate(this.txMgr);
   boolean rollbackOnly = task instanceof DefaultRollback && !isTxRunning();
   RunInTx tx = new RunInTx(action, rollbackOnly);
   if (txLogger.isInfoEnabled()) {
     if (isTxRunning()) {
       txLogger.info("tx is running executing \"" + task.getName() + "\" in current tx");
     } else {
       txLogger.info("no tx running, wrapping execution of \"" + task.getName() + "\" in tx");
       if (rollbackOnly) {
         txLogger.info("rollback enabled for \"" + task.getName() + "\"");
       }
     }
   }
   Object rtn = null;
   try {
     rtn = txTemplate.execute(tx);
   } catch (Throwable ex) {
     // The following logic intends to display a sensible message for the user when a column
     // contains a value whose length
     // exceeds the maximum length allowed in the database.  The logic has been tested on MySQL,
     // Postgres, Oracle and
     // SQLServer so far.
     if (ex.getCause() instanceof java.sql.BatchUpdateException) { // Oracle
       String msg =
           ((java.sql.BatchUpdateException) ex.getCause()).getNextException().getMessage();
       if (msg != null) {
         ex.printStackTrace();
         throw new WMRuntimeException(msg);
       }
     } else if (ex.getCause().getCause() instanceof java.sql.BatchUpdateException) { // Postgres
       java.sql.BatchUpdateException e = (java.sql.BatchUpdateException) ex.getCause().getCause();
       if (e != null && e.getMessage() != null) {
         ex.printStackTrace();
         throw new WMRuntimeException(e.getNextException().getMessage());
       }
     } else if (ex.getCause().getCause() != null) { // MySQL, SQLServer
       String msg = ex.getCause().getCause().getMessage();
       if (msg != null) {
         ex.printStackTrace();
         throw new WMRuntimeException(msg);
       }
     } else {
       throw new WMRuntimeException(ex);
     }
   }
   if (txLogger.isInfoEnabled()) {
     if (isTxRunning()) {
       txLogger.info("tx is running after execution of \"" + task.getName() + "\"");
     } else {
       txLogger.info("tx is not running after execution of \"" + task.getName() + "\"");
     }
   }
   return rtn;
 }
 @Override
 public synchronized void write(final Record record) {
   try {
     final RecordDefinition recordDefinition = record.getRecordDefinition();
     final RecordStore recordStore = recordDefinition.getRecordStore();
     final RecordState state = record.getState();
     if (recordStore != this.recordStore) {
       if (state != RecordState.DELETED) {
         insert(record);
       }
     } else {
       switch (state) {
         case NEW:
           insert(record);
           break;
         case MODIFIED:
           update(record);
           break;
         case PERSISTED:
           // No action required
           break;
         case DELETED:
           delete(record);
           break;
         default:
           throw new IllegalStateException("State not known");
       }
     }
   } catch (final RuntimeException e) {
     throw e;
   } catch (final Error e) {
     throw e;
   } catch (final BatchUpdateException e) {
     for (SQLException e1 = e.getNextException(); e1 != null; e1 = e1.getNextException()) {
       LOG.error("Unable to write", e1);
     }
     throw new RuntimeException("Unable to write", e);
   } catch (final Exception e) {
     throw new RuntimeException("Unable to write", e);
   }
 }