Alfresco advise the programmer once you need to make a transaction into the repository to use RetryingTransactionHandler to achieve the transaction.
Can anyone give me a clarification bout that ?
specifically i'm talking about code like this
RetryingTransactionCallback<String> callback = new RetryingTransactionCallback<String>(){
public String execute() throws Throwable {
// doProcess must be invoked within user context.
AuthenticationUtil.runAs(new RunAsWork<String>(){
public String doWork()throws Exception{
try {
if(getOperationType().equals(OperationTypes.CREATE_ORGANIZATION_OPERATION)){
RetryingTransactionHelper txnHelper =
Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance());
txnHelper.doInTransaction(doProcessActionCallbackOperations.CreateOrganizationCallback, false, true);
}
} catch(Throwable e){
}
return "";
}
}, AuthenticationUtil.getSystemUserName());
return "";
}
};
try {
RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance());
txnHelper.doInTransaction(callback, false, true);
} catch (Throwable e) {
if (e instanceof ReportedException == false) {
Utils.addErrorMessage(formatErrorMessage(e), e);
}
ReportedException.throwIfNecessary(e);
}
Also, as you are notice i use AuthenticationUtils.runAs().
So can you help me to understand different keys in this code like RetryingTransaction & AuthenticationUtils ?
The RetryingTransactionHelper
ensures the callback
you provide is executed within a transaction. Moreover, as the name suggests, if the transaction fails for some reasons (e.g. an Exception is thrown in the callback
code that's not properly caught, or you try to change the same content in the repository concurrently from two different threads), the same transaction will be properly rolled back and re-executed ("retried") a configurable amount of times (default: 20). This is handier than manually handling transactions more often than not.
In the code you posted, you are nesting the call to doProcessActionCallbackOperations.CreateOrganizationCallback
in two transactions (because of the last parameter of doInTransaction
being always true
, i.e. requiresNew
), the outer being created before callback
gets executed, the inner the one created within the callback
itself. It seems to me that you could get rid of the inner transaction, but that's up to you. Transactions can be nested, even though failures in an inner transaction will most likely invalidate the whole stack of transactions.
The AuthenticationUtils.runAs
facility allows you to execute pieces of logic using an authority in general different from the current user. Internally, user credentials are stored as ThreadLocal
parameters. In you case, the AuthenticationUtil.runAs
takes care of temporarily change such ThreadLocal
to allow the inner callback to always execute with the highest permission level (i.e. system) regardless of which user is executing the code. There are also situations where there's no logged in user currently set, e.g. within scheduled jobs. Then the AuthenticationUtils.runAs
allows you to access the content into the repository, usually specifying system
or admin
users.