diff --git a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java index 322d36d0e4..5d28d0cc6f 100644 --- a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java +++ b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java @@ -46,10 +46,11 @@ import javax.faces.render.RenderKitFactory; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.web.app.Application; import org.alfresco.web.bean.repository.Repository; @@ -88,7 +89,6 @@ public class InvokeCommand extends BaseAjaxCommand final HttpServletResponse response) throws ServletException, IOException { - UserTransaction tx = null; ResponseWriter writer = null; try { @@ -153,20 +153,21 @@ public class InvokeCommand extends BaseAjaxCommand facesContext); // setup the transaction - tx = Repository.getUserTransaction(facesContext); - tx.begin(); - - // invoke the method - method.invoke(bean); - - // commit - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + final Object beanFinal = bean; + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // invoke the method + method.invoke(beanFinal); + return null; + } + }; + txnHelper.doInTransaction(callback); } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) { tx.rollback(); } } catch (Exception ex) { } - if (err instanceof EvaluationException) { final Throwable cause = ((EvaluationException)err).getCause(); diff --git a/source/java/org/alfresco/web/bean/AdvancedSearchBean.java b/source/java/org/alfresco/web/bean/AdvancedSearchBean.java index eafb853982..181c06f19b 100644 --- a/source/java/org/alfresco/web/bean/AdvancedSearchBean.java +++ b/source/java/org/alfresco/web/bean/AdvancedSearchBean.java @@ -39,12 +39,13 @@ import javax.faces.event.ActionEvent; import javax.faces.model.DataModel; import javax.faces.model.ListDataModel; import javax.faces.model.SelectItem; -import javax.transaction.UserTransaction; import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.ExpiringValueCache; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; @@ -984,45 +985,48 @@ public class AdvancedSearchBean searchesRef = getUserSearchesRef(); } - SearchContext search = this.navigator.getSearchContext(); + final SearchContext search = this.navigator.getSearchContext(); if (searchesRef != null && search != null) { - UserTransaction tx = null; try { - FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - // create new content node as the saved search object - Map props = new HashMap(2, 1.0f); - props.put(ContentModel.PROP_NAME, this.searchName); - props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription); - ChildAssociationRef childRef = this.nodeService.createNode( - searchesRef, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(this.searchName)), - ContentModel.TYPE_CONTENT, - props); - - ContentService contentService = Repository.getServiceRegistry(context).getContentService(); - ContentWriter writer = contentService.getWriter(childRef.getChildRef(), ContentModel.PROP_CONTENT, true); - - // get a writer to our new node ready for XML content - writer.setMimetype(MimetypeMap.MIMETYPE_XML); - writer.setEncoding("UTF-8"); - - // output an XML serialized version of the SearchContext object - writer.putContent(search.toXML()); - - tx.commit(); + final FacesContext context = FacesContext.getCurrentInstance(); + final NodeRef searchesRefFinal = searchesRef; + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // create new content node as the saved search object + Map props = new HashMap(2, 1.0f); + props.put(ContentModel.PROP_NAME, searchName); + props.put(ContentModel.PROP_DESCRIPTION, searchDescription); + ChildAssociationRef childRef = nodeService.createNode( + searchesRefFinal, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(searchName)), + ContentModel.TYPE_CONTENT, + props); + + ContentService contentService = Repository.getServiceRegistry(context).getContentService(); + ContentWriter writer = contentService.getWriter(childRef.getChildRef(), ContentModel.PROP_CONTENT, true); + + // get a writer to our new node ready for XML content + writer.setMimetype(MimetypeMap.MIMETYPE_XML); + writer.setEncoding("UTF-8"); + + // output an XML serialized version of the SearchContext object + writer.putContent(search.toXML()); + return null; + } + }; + txnHelper.doInTransaction(callback); this.cachedSavedSearches.clear(); this.savedSearch = null; } catch (Throwable e) { - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_SAVE_SEARCH), e.getMessage()), e); outcome = null; @@ -1039,45 +1043,47 @@ public class AdvancedSearchBean { String outcome = OUTCOME_BROWSE; - SearchContext search = this.navigator.getSearchContext(); + final SearchContext search = this.navigator.getSearchContext(); if (search != null) { - UserTransaction tx = null; try { - FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - // handle Edit e.g. Overwrite of existing search - // detect if was previously selected saved search (e.g. NodeRef not null) - NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch); - if (this.nodeService.exists(searchRef)) + final FacesContext context = FacesContext.getCurrentInstance(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - Map props = this.nodeService.getProperties(searchRef); - props.put(ContentModel.PROP_NAME, this.searchName); - props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription); - this.nodeService.setProperties(searchRef, props); - - ContentService contentService = Repository.getServiceRegistry(context).getContentService(); - ContentWriter writer = contentService.getWriter(searchRef, ContentModel.PROP_CONTENT, true); - - // get a writer to our new node ready for XML content - writer.setMimetype(MimetypeMap.MIMETYPE_XML); - writer.setEncoding("UTF-8"); - - // output an XML serialized version of the SearchContext object - writer.putContent(search.toXML()); - - tx.commit(); - } + public Object execute() throws Throwable + { + // handle Edit e.g. Overwrite of existing search + // detect if was previously selected saved search (e.g. NodeRef not null) + NodeRef searchRef = new NodeRef(Repository.getStoreRef(), savedSearch); + if (nodeService.exists(searchRef)) + { + Map props = nodeService.getProperties(searchRef); + props.put(ContentModel.PROP_NAME, searchName); + props.put(ContentModel.PROP_DESCRIPTION, searchDescription); + nodeService.setProperties(searchRef, props); + + ContentService contentService = Repository.getServiceRegistry(context).getContentService(); + ContentWriter writer = contentService.getWriter(searchRef, ContentModel.PROP_CONTENT, true); + + // get a writer to our new node ready for XML content + writer.setMimetype(MimetypeMap.MIMETYPE_XML); + writer.setEncoding("UTF-8"); + + // output an XML serialized version of the SearchContext object + writer.putContent(search.toXML()); + } + return null; + } + }; + txnHelper.doInTransaction(callback); this.cachedSavedSearches.clear(); this.savedSearch = null; } catch (Throwable e) { - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_SAVE_SEARCH), e.getMessage()), e); outcome = null; diff --git a/source/java/org/alfresco/web/bean/BaseDetailsBean.java b/source/java/org/alfresco/web/bean/BaseDetailsBean.java index 5b96c2e07c..9e73c6b16b 100644 --- a/source/java/org/alfresco/web/bean/BaseDetailsBean.java +++ b/source/java/org/alfresco/web/bean/BaseDetailsBean.java @@ -32,11 +32,12 @@ import java.util.Map; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; -import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ApplicationModel; import org.alfresco.model.ContentModel; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.FileTypeImageSize; import org.alfresco.service.cmr.repository.NodeRef; @@ -371,79 +372,80 @@ public abstract class BaseDetailsBean { String outcome = "cancel"; - UserTransaction tx = null; - try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // firstly retrieve all the properties for the current node - Map updateProps = this.nodeService.getProperties( - getNode().getNodeRef()); - - // update the simple workflow properties - - // set the approve step name - updateProps.put(ApplicationModel.PROP_APPROVE_STEP, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_STEP_NAME)); - - // specify whether the approve step will copy or move the content - boolean approveMove = true; - String approveAction = (String)this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_ACTION); - if (approveAction != null && approveAction.equals("copy")) + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - approveMove = false; - } - updateProps.put(ApplicationModel.PROP_APPROVE_MOVE, Boolean.valueOf(approveMove)); - - // create node ref representation of the destination folder - updateProps.put(ApplicationModel.PROP_APPROVE_FOLDER, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_FOLDER)); - - // determine whether there should be a reject step - boolean requireReject = true; - String rejectStepPresent = (String)this.workflowProperties.get( - SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT); - if (rejectStepPresent != null && rejectStepPresent.equals("no")) - { - requireReject = false; - } - - if (requireReject) - { - // set the reject step name - updateProps.put(ApplicationModel.PROP_REJECT_STEP, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_STEP_NAME)); - - // specify whether the reject step will copy or move the content - boolean rejectMove = true; - String rejectAction = (String)this.workflowProperties.get( - SimpleWorkflowHandler.PROP_REJECT_ACTION); - if (rejectAction != null && rejectAction.equals("copy")) + public Object execute() throws Throwable { - rejectMove = false; - } - updateProps.put(ApplicationModel.PROP_REJECT_MOVE, Boolean.valueOf(rejectMove)); + // firstly retrieve all the properties for the current node + Map updateProps = nodeService.getProperties( + getNode().getNodeRef()); + + // update the simple workflow properties + + // set the approve step name + updateProps.put(ApplicationModel.PROP_APPROVE_STEP, + workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_STEP_NAME)); + + // specify whether the approve step will copy or move the content + boolean approveMove = true; + String approveAction = (String)workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_ACTION); + if (approveAction != null && approveAction.equals("copy")) + { + approveMove = false; + } + updateProps.put(ApplicationModel.PROP_APPROVE_MOVE, Boolean.valueOf(approveMove)); + + // create node ref representation of the destination folder + updateProps.put(ApplicationModel.PROP_APPROVE_FOLDER, + workflowProperties.get(SimpleWorkflowHandler.PROP_APPROVE_FOLDER)); + + // determine whether there should be a reject step + boolean requireReject = true; + String rejectStepPresent = (String)workflowProperties.get( + SimpleWorkflowHandler.PROP_REJECT_STEP_PRESENT); + if (rejectStepPresent != null && rejectStepPresent.equals("no")) + { + requireReject = false; + } + + if (requireReject) + { + // set the reject step name + updateProps.put(ApplicationModel.PROP_REJECT_STEP, + workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_STEP_NAME)); + + // specify whether the reject step will copy or move the content + boolean rejectMove = true; + String rejectAction = (String)workflowProperties.get( + SimpleWorkflowHandler.PROP_REJECT_ACTION); + if (rejectAction != null && rejectAction.equals("copy")) + { + rejectMove = false; + } + updateProps.put(ApplicationModel.PROP_REJECT_MOVE, Boolean.valueOf(rejectMove)); - // create node ref representation of the destination folder - updateProps.put(ApplicationModel.PROP_REJECT_FOLDER, - this.workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_FOLDER)); - } - else - { - // set all the reject properties to null to signify there should - // be no reject step - updateProps.put(ApplicationModel.PROP_REJECT_STEP, null); - updateProps.put(ApplicationModel.PROP_REJECT_MOVE, null); - updateProps.put(ApplicationModel.PROP_REJECT_FOLDER, null); - } - - // set the properties on the node - this.nodeService.setProperties(getNode().getNodeRef(), updateProps); - - // commit the transaction - tx.commit(); + // create node ref representation of the destination folder + updateProps.put(ApplicationModel.PROP_REJECT_FOLDER, + workflowProperties.get(SimpleWorkflowHandler.PROP_REJECT_FOLDER)); + } + else + { + // set all the reject properties to null to signify there should + // be no reject step + updateProps.put(ApplicationModel.PROP_REJECT_STEP, null); + updateProps.put(ApplicationModel.PROP_REJECT_MOVE, null); + updateProps.put(ApplicationModel.PROP_REJECT_FOLDER, null); + } + + // set the properties on the node + nodeService.setProperties(getNode().getNodeRef(), updateProps); + return null; + } + }; + txnHelper.doInTransaction(callback); // reset the state of the current document so it reflects the changes just made getNode().reset(); @@ -452,7 +454,6 @@ public abstract class BaseDetailsBean } catch (Throwable e) { - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE_SIMPLEWORKFLOW), e.getMessage()), e); } @@ -493,19 +494,21 @@ public abstract class BaseDetailsBean throw new AlfrescoRuntimeException("approve called without an id"); } - NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); + final NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); - UserTransaction tx = null; try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // call the service to perform the approve - WorkflowUtil.approve(docNodeRef, this.nodeService, this.copyService); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // call the service to perform the approve + WorkflowUtil.approve(docNodeRef, nodeService, copyService); + return null; + } + }; + txnHelper.doInTransaction(callback); // if this was called via the document details dialog we need to reset the document node if (getNode() != null) @@ -518,8 +521,6 @@ public abstract class BaseDetailsBean } catch (Throwable e) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_WORKFLOW_APPROVE), e.getMessage()), e); } @@ -558,19 +559,21 @@ public abstract class BaseDetailsBean throw new AlfrescoRuntimeException("reject called without an id"); } - NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); + final NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id); - UserTransaction tx = null; try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // call the service to perform the reject - WorkflowUtil.reject(docNodeRef, this.nodeService, this.copyService); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // call the service to perform the reject + WorkflowUtil.reject(docNodeRef, nodeService, copyService); + return null; + } + }; + txnHelper.doInTransaction(callback); // if this was called via the document details dialog we need to reset the document node if (getNode() != null) @@ -584,7 +587,6 @@ public abstract class BaseDetailsBean catch (Throwable e) { // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_WORKFLOW_REJECT), e.getMessage()), e); } @@ -649,33 +651,32 @@ public abstract class BaseDetailsBean /** * Action Handler to take Ownership of the current Space */ - public void takeOwnership(ActionEvent event) + public void takeOwnership(final ActionEvent event) { - FacesContext fc = FacesContext.getCurrentInstance(); - - UserTransaction tx = null; + final FacesContext fc = FacesContext.getCurrentInstance(); try { - tx = Repository.getUserTransaction(fc); - tx.begin(); - - this.ownableService.takeOwnership(getNode().getNodeRef()); - - String msg = Application.getMessage(fc, MSG_SUCCESS_OWNERSHIP); - FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); - String formId = Utils.getParentForm(fc, event.getComponent()).getClientId(fc); - fc.addMessage(formId + ':' + getPropertiesPanelId(), facesMsg); - - getNode().reset(); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + ownableService.takeOwnership(getNode().getNodeRef()); + + String msg = Application.getMessage(fc, MSG_SUCCESS_OWNERSHIP); + FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); + String formId = Utils.getParentForm(fc, event.getComponent()).getClientId(fc); + fc.addMessage(formId + ':' + getPropertiesPanelId(), facesMsg); + + getNode().reset(); + return null; + } + }; + txnHelper.doInTransaction(callback); } catch (Throwable e) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( fc, Repository.ERROR_GENERIC), e.getMessage()), e); } diff --git a/source/java/org/alfresco/web/bean/CategoriesBean.java b/source/java/org/alfresco/web/bean/CategoriesBean.java index 15f7a825f8..22ab8e4367 100644 --- a/source/java/org/alfresco/web/bean/CategoriesBean.java +++ b/source/java/org/alfresco/web/bean/CategoriesBean.java @@ -38,6 +38,8 @@ import javax.faces.event.ActionEvent; import javax.transaction.UserTransaction; import org.alfresco.model.ContentModel; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; @@ -447,36 +449,36 @@ public class CategoriesBean implements IContextListener { String outcome = DEFAULT_OUTCOME; - UserTransaction tx = null; try { FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - // create category using categoryservice - NodeRef ref; - if (categoryRef == null) + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(context); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - ref = this.categoryService.createRootCategory(Repository.getStoreRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, this.name); - } - else - { - ref = this.categoryService.createCategory(categoryRef, this.name); - } - - // apply the titled aspect - for description - Map titledProps = new HashMap(1, 1.0f); - titledProps.put(ContentModel.PROP_DESCRIPTION, this.description); - this.nodeService.addAspect(ref, ContentModel.ASPECT_TITLED, titledProps); - - // commit the transaction - tx.commit(); + public Object execute() throws Throwable + { + // create category using categoryservice + NodeRef ref; + if (categoryRef == null) + { + ref = categoryService.createRootCategory(Repository.getStoreRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, name); + } + else + { + ref = categoryService.createCategory(categoryRef, name); + } + + // apply the titled aspect - for description + Map titledProps = new HashMap(1, 1.0f); + titledProps.put(ContentModel.PROP_DESCRIPTION, description); + nodeService.addAspect(ref, ContentModel.ASPECT_TITLED, titledProps); + return null; + } + }; + txnHelper.doInTransaction(callback); } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err); outcome = null; @@ -492,31 +494,33 @@ public class CategoriesBean implements IContextListener { String outcome = DEFAULT_OUTCOME; - UserTransaction tx = null; try { FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - // update the category node - NodeRef nodeRef = getActionCategory().getNodeRef(); - this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, this.name); - - // apply the titled aspect - for description - if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TITLED) == false) + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(context); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - Map titledProps = new HashMap(1, 1.0f); - titledProps.put(ContentModel.PROP_DESCRIPTION, this.description); - this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, titledProps); - } - else - { - this.nodeService.setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, this.description); - } - - // commit the transaction - tx.commit(); + public NodeRef execute() throws Throwable + { + // update the category node + NodeRef nodeRef = getActionCategory().getNodeRef(); + nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, name); + + // apply the titled aspect - for description + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TITLED) == false) + { + Map titledProps = new HashMap(1, 1.0f); + titledProps.put(ContentModel.PROP_DESCRIPTION, description); + nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, titledProps); + } + else + { + nodeService.setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, description); + } + return nodeRef; + } + }; + NodeRef nodeRef = txnHelper.doInTransaction(callback); // edit the node in the breadcrumb if required List location = getLocation(); @@ -533,8 +537,6 @@ public class CategoriesBean implements IContextListener } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err); outcome = null; @@ -552,44 +554,46 @@ public class CategoriesBean implements IContextListener if (getActionCategory() != null) { - UserTransaction tx = null; try { FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - // delete the category node using the nodeservice - NodeRef categoryNodeRef = getActionCategory().getNodeRef(); - this.categoryService.deleteCategory(categoryNodeRef); - - // if there are other items in the repository using this category - // all the associations to the category should be removed too - if (this.members != null && this.members.size() > 0) + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(context); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - for (ChildAssociationRef childRef : this.members) + public NodeRef execute() throws Throwable { - List list = new ArrayList(this.members.size()); + // delete the category node using the nodeservice + NodeRef categoryNodeRef = getActionCategory().getNodeRef(); + categoryService.deleteCategory(categoryNodeRef); - NodeRef member = childRef.getChildRef(); - Collection categories = (Collection)this.nodeService. - getProperty(member, ContentModel.PROP_CATEGORIES); - - for (NodeRef category : categories) + // if there are other items in the repository using this category + // all the associations to the category should be removed too + if (members != null && members.size() > 0) { - if (category.equals(categoryNodeRef) == false) + for (ChildAssociationRef childRef : members) { - list.add(category); + List list = new ArrayList(members.size()); + + NodeRef member = childRef.getChildRef(); + Collection categories = (Collection)nodeService. + getProperty(member, ContentModel.PROP_CATEGORIES); + + for (NodeRef category : categories) + { + if (category.equals(categoryNodeRef) == false) + { + list.add(category); + } + } + + // persist the list back to the repository + nodeService.setProperty(member, ContentModel.PROP_CATEGORIES, (Serializable)list); } } - - // persist the list back to the repository - this.nodeService.setProperty(member, ContentModel.PROP_CATEGORIES, (Serializable)list); + return categoryNodeRef; } - } - - // commit the transaction - tx.commit(); + }; + NodeRef categoryNodeRef = txnHelper.doInTransaction(callback); // remove this node from the breadcrumb if required List location = getLocation(); @@ -613,8 +617,6 @@ public class CategoriesBean implements IContextListener } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err); outcome = null; @@ -715,6 +717,7 @@ public class CategoriesBean implements IContextListener /** * @see org.alfresco.web.ui.common.component.IBreadcrumbHandler#navigationOutcome(org.alfresco.web.ui.common.component.UIBreadcrumb) */ + @SuppressWarnings("unchecked") public String navigationOutcome(UIBreadcrumb breadcrumb) { // All category breadcrumb elements relate to a Categiry Node Id diff --git a/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java b/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java index 5836775611..3e5e7be311 100644 --- a/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java +++ b/source/java/org/alfresco/web/bean/CheckinCheckoutBean.java @@ -30,11 +30,12 @@ import java.util.Map; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; -import javax.transaction.UserTransaction; import org.alfresco.model.ApplicationModel; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.version.VersionModel; import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.service.cmr.coci.CheckOutCheckInService; @@ -453,86 +454,85 @@ public class CheckinCheckoutBean String outcome = null; boolean checkoutSuccessful = false; - UserTransaction tx = null; - - Node node = getDocument(); + final Node node = getDocument(); if (node != null) { try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to checkout content node Id: " + node.getId()); - - // checkout the node content to create a working copy - if (logger.isDebugEnabled()) + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - logger.debug("Checkout copy location: " + getCopyLocation()); - logger.debug("Selected Space Id: " + this.selectedSpaceId); - } - NodeRef workingCopyRef = null; - if (getCopyLocation().equals(COPYLOCATION_OTHER) && this.selectedSpaceId != null) - { - // checkout to a arbituary parent Space - NodeRef destRef = this.selectedSpaceId; - - ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(destRef); - workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef(), - destRef, ContentModel.ASSOC_CONTAINS, childAssocRef.getQName()); - } - else - { - // checkout the content to the current space - workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef()); - - // if this is a workflow action and there is a task id present we need - // to also link the working copy to the workflow package so it appears - // in the resources panel in the manage task dialog - if (this.isWorkflowAction && this.workflowTaskId != null && - (this.workflowTaskId.equals("null") == false)) + public Object execute() throws Throwable { - WorkflowTask task = this.workflowService.getTaskById(this.workflowTaskId); - if (task != null) + if (logger.isDebugEnabled()) + logger.debug("Trying to checkout content node Id: " + node.getId()); + + // checkout the node content to create a working copy + if (logger.isDebugEnabled()) { - NodeRef workflowPackage = (NodeRef)task.properties.get(WorkflowModel.ASSOC_PACKAGE); - if (workflowPackage != null) + logger.debug("Checkout copy location: " + getCopyLocation()); + logger.debug("Selected Space Id: " + selectedSpaceId); + } + NodeRef workingCopyRef = null; + if (getCopyLocation().equals(COPYLOCATION_OTHER) && selectedSpaceId != null) + { + // checkout to a arbituary parent Space + NodeRef destRef = selectedSpaceId; + + ChildAssociationRef childAssocRef = nodeService.getPrimaryParent(destRef); + workingCopyRef = versionOperationsService.checkout(node.getNodeRef(), + destRef, ContentModel.ASSOC_CONTAINS, childAssocRef.getQName()); + } + else + { + // checkout the content to the current space + workingCopyRef = versionOperationsService.checkout(node.getNodeRef()); + + // if this is a workflow action and there is a task id present we need + // to also link the working copy to the workflow package so it appears + // in the resources panel in the manage task dialog + if (isWorkflowAction && workflowTaskId != null && + (workflowTaskId.equals("null") == false)) { - this.nodeService.addChild(workflowPackage, workingCopyRef, - ContentModel.ASSOC_CONTAINS, QName.createQName( - NamespaceService.CONTENT_MODEL_1_0_URI, - QName.createValidLocalName((String)this.nodeService.getProperty( - workingCopyRef, ContentModel.PROP_NAME)))); - - if (logger.isDebugEnabled()) - logger.debug("Added working copy to workflow package: " + workflowPackage); + WorkflowTask task = workflowService.getTaskById(workflowTaskId); + if (task != null) + { + NodeRef workflowPackage = (NodeRef)task.properties.get(WorkflowModel.ASSOC_PACKAGE); + if (workflowPackage != null) + { + nodeService.addChild(workflowPackage, workingCopyRef, + ContentModel.ASSOC_CONTAINS, QName.createQName( + NamespaceService.CONTENT_MODEL_1_0_URI, + QName.createValidLocalName((String)nodeService.getProperty( + workingCopyRef, ContentModel.PROP_NAME)))); + + if (logger.isDebugEnabled()) + logger.debug("Added working copy to workflow package: " + workflowPackage); + } + } } } + + // set the working copy Node instance + Node workingCopy = new Node(workingCopyRef); + setWorkingDocument(workingCopy); + + // create content URL to the content download servlet with ID and expected filename + // the myfile part will be ignored by the servlet but gives the browser a hint + String url = DownloadContentServlet.generateDownloadURL(workingCopyRef, workingCopy.getName()); + + workingCopy.getProperties().put("url", url); + workingCopy.getProperties().put("fileType32", Utils.getFileTypeImage(workingCopy.getName(), false)); + return null; } - } - - // set the working copy Node instance - Node workingCopy = new Node(workingCopyRef); - setWorkingDocument(workingCopy); - - // create content URL to the content download servlet with ID and expected filename - // the myfile part will be ignored by the servlet but gives the browser a hint - String url = DownloadContentServlet.generateDownloadURL(workingCopyRef, workingCopy.getName()); - - workingCopy.getProperties().put("url", url); - workingCopy.getProperties().put("fileType32", Utils.getFileTypeImage(workingCopy.getName(), false)); - - // commit the transaction - tx.commit(); + }; + txnHelper.doInTransaction(callback); // mark as successful checkoutSuccessful = true; } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} Utils.addErrorMessage(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_CHECKOUT) + err.getMessage(), err); } @@ -689,25 +689,26 @@ public class CheckinCheckoutBean { String outcome = null; - UserTransaction tx = null; - - Node node = getDocument(); + final Node node = getDocument(); if (node != null) { try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to update content node Id: " + node.getId()); - - // get an updating writer that we can use to modify the content on the current node - ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); - writer.putContent(this.editorOutput); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + if (logger.isDebugEnabled()) + logger.debug("Trying to update content node Id: " + node.getId()); + + // get an updating writer that we can use to modify the content on the current node + ContentWriter writer = contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); + writer.putContent(editorOutput); + return null; + } + }; + txnHelper.doInTransaction(callback); // clean up and clear action context resetState(); @@ -719,8 +720,6 @@ public class CheckinCheckoutBean } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} Utils.addErrorMessage(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage()); } @@ -828,66 +827,67 @@ public class CheckinCheckoutBean { String outcome = null; - UserTransaction tx = null; - // NOTE: for checkin the document node _is_ the working document! - Node node = getDocument(); + final Node node = getDocument(); if (node != null && (getCopyLocation().equals(COPYLOCATION_CURRENT) || this.getFileName() != null)) { try { - FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to checkin content node Id: " + node.getId()); - - // we can either checkin the content from the current working copy node - // which would have been previously updated by the user - String contentUrl; - if (getCopyLocation().equals(COPYLOCATION_CURRENT)) + final FacesContext context = FacesContext.getCurrentInstance(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - ContentData contentData = (ContentData) node.getProperties().get(ContentModel.PROP_CONTENT); - contentUrl = (contentData == null ? null : contentData.getContentUrl()); - } - // or specify a specific file as the content instead - else - { - // add the content to an anonymous but permanent writer location - // we can then retrieve the URL to the content to to be set on the node during checkin - ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); - // also update the mime type in case a different type of file is uploaded - String mimeType = Repository.getMimeTypeForFileName(context, this.fileName); - writer.setMimetype(mimeType); - writer.putContent(this.file); - contentUrl = writer.getContentUrl(); - } - - if (contentUrl == null || contentUrl.length() == 0) - { - throw new IllegalStateException("Content URL is empty for specified working copy content node!"); - } - - // add version history text to props - Map props = new HashMap(1, 1.0f); - props.put(Version.PROP_DESCRIPTION, this.versionNotes); - // set the flag for minor or major change - if (this.minorChange) - { - props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); - } - else - { - props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR); - } - - // perform the checkin - this.versionOperationsService.checkin(node.getNodeRef(), - props, contentUrl, this.keepCheckedOut); - - // commit the transaction - tx.commit(); + public Object execute() throws Throwable + { + if (logger.isDebugEnabled()) + logger.debug("Trying to checkin content node Id: " + node.getId()); + + // we can either checkin the content from the current working copy node + // which would have been previously updated by the user + String contentUrl; + if (getCopyLocation().equals(COPYLOCATION_CURRENT)) + { + ContentData contentData = (ContentData) node.getProperties().get(ContentModel.PROP_CONTENT); + contentUrl = (contentData == null ? null : contentData.getContentUrl()); + } + // or specify a specific file as the content instead + else + { + // add the content to an anonymous but permanent writer location + // we can then retrieve the URL to the content to to be set on the node during checkin + ContentWriter writer = contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); + // also update the mime type in case a different type of file is uploaded + String mimeType = Repository.getMimeTypeForFileName(context, fileName); + writer.setMimetype(mimeType); + writer.putContent(file); + contentUrl = writer.getContentUrl(); + } + + if (contentUrl == null || contentUrl.length() == 0) + { + throw new IllegalStateException("Content URL is empty for specified working copy content node!"); + } + + // add version history text to props + Map props = new HashMap(1, 1.0f); + props.put(Version.PROP_DESCRIPTION, versionNotes); + // set the flag for minor or major change + if (minorChange) + { + props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR); + } + else + { + props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR); + } + + // perform the checkin + versionOperationsService.checkin(node.getNodeRef(), + props, contentUrl, keepCheckedOut); + return null; + } + }; + txnHelper.doInTransaction(callback); outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME; @@ -902,8 +902,6 @@ public class CheckinCheckoutBean } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} Utils.addErrorMessage(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_CHECKIN) + err.getMessage(), err); } @@ -923,32 +921,33 @@ public class CheckinCheckoutBean { String outcome = null; - UserTransaction tx = null; - // NOTE: for update the document node _is_ the working document! - Node node = getDocument(); + final Node node = getDocument(); if (node != null && this.getFileName() != null) { try { - FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - if (logger.isDebugEnabled()) - logger.debug("Trying to update content node Id: " + node.getId()); - - // get an updating writer that we can use to modify the content on the current node - ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); - - // also update the mime type in case a different type of file is uploaded - String mimeType = Repository.getMimeTypeForFileName(context, this.fileName); - writer.setMimetype(mimeType); - - writer.putContent(this.file); - - // commit the transaction - tx.commit(); + final FacesContext context = FacesContext.getCurrentInstance(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + if (logger.isDebugEnabled()) + logger.debug("Trying to update content node Id: " + node.getId()); + + // get an updating writer that we can use to modify the content on the current node + ContentWriter writer = contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true); + + // also update the mime type in case a different type of file is uploaded + String mimeType = Repository.getMimeTypeForFileName(context, fileName); + writer.setMimetype(mimeType); + + writer.putContent(file); + return null; + } + }; + txnHelper.doInTransaction(callback); // clear action context setDocument(null); @@ -958,8 +957,6 @@ public class CheckinCheckoutBean } catch (Throwable err) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} Utils.addErrorMessage(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage(), err); } diff --git a/source/java/org/alfresco/web/bean/DocumentDetailsBean.java b/source/java/org/alfresco/web/bean/DocumentDetailsBean.java index bf364da97e..71d748dd12 100644 --- a/source/java/org/alfresco/web/bean/DocumentDetailsBean.java +++ b/source/java/org/alfresco/web/bean/DocumentDetailsBean.java @@ -36,11 +36,12 @@ import java.util.Map; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; -import javax.transaction.UserTransaction; import org.alfresco.model.ApplicationModel; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.ml.ContentFilterLanguagesService; @@ -412,25 +413,25 @@ public class DocumentDetailsBean extends BaseDetailsBean { String outcome = "cancel"; - UserTransaction tx = null; - try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // firstly retrieve all the properties for the current node - Map updateProps = this.nodeService.getProperties( - getDocument().getNodeRef()); - - // create a node ref representation of the selected id and set the new properties - updateProps.put(ContentModel.PROP_CATEGORIES, (Serializable)this.categories); - - // set the properties on the node - this.nodeService.setProperties(getDocument().getNodeRef(), updateProps); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // firstly retrieve all the properties for the current node + Map updateProps = nodeService.getProperties(getDocument().getNodeRef()); + + // create a node ref representation of the selected id and set the new properties + updateProps.put(ContentModel.PROP_CATEGORIES, (Serializable) categories); + + // set the properties on the node + nodeService.setProperties(getDocument().getNodeRef(), updateProps); + return null; + } + }; + txnHelper.doInTransaction(callback); // reset the state of the current document so it reflects the changes just made getDocument().reset(); @@ -439,7 +440,6 @@ public class DocumentDetailsBean extends BaseDetailsBean } catch (Throwable e) { - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE_CATEGORY), e.getMessage()), e); } @@ -452,26 +452,25 @@ public class DocumentDetailsBean extends BaseDetailsBean */ public void applyClassifiable() { - UserTransaction tx = null; - try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // add the general classifiable aspect to the node - this.nodeService.addAspect(getDocument().getNodeRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, null); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // add the general classifiable aspect to the node + nodeService.addAspect(getDocument().getNodeRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, null); + return null; + } + }; + txnHelper.doInTransaction(callback); // reset the state of the current document getDocument().reset(); } catch (Throwable e) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_ASPECT_CLASSIFY), e.getMessage()), e); } @@ -482,26 +481,25 @@ public class DocumentDetailsBean extends BaseDetailsBean */ public void applyVersionable() { - UserTransaction tx = null; - try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // add the versionable aspect to the node - this.nodeService.addAspect(getDocument().getNodeRef(), ContentModel.ASPECT_VERSIONABLE, null); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // add the versionable aspect to the node + nodeService.addAspect(getDocument().getNodeRef(), ContentModel.ASPECT_VERSIONABLE, null); + return null; + } + }; + txnHelper.doInTransaction(callback); // reset the state of the current document getDocument().reset(); } catch (Throwable e) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_ASPECT_VERSIONING), e.getMessage()), e); } @@ -510,33 +508,32 @@ public class DocumentDetailsBean extends BaseDetailsBean /** * Action Handler to unlock a locked document */ - public void unlock(ActionEvent event) + public void unlock(final ActionEvent event) { - FacesContext fc = FacesContext.getCurrentInstance(); - - UserTransaction tx = null; + final FacesContext fc = FacesContext.getCurrentInstance(); try { - tx = Repository.getUserTransaction(fc); - tx.begin(); - - this.lockService.unlock(getNode().getNodeRef()); - - String msg = Application.getMessage(fc, MSG_SUCCESS_UNLOCK); - FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); - String formId = Utils.getParentForm(fc, event.getComponent()).getClientId(fc); - fc.addMessage(formId + ':' + getPropertiesPanelId(), facesMsg); - - getNode().reset(); - - // commit the transaction - tx.commit(); + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + lockService.unlock(getNode().getNodeRef()); + + String msg = Application.getMessage(fc, MSG_SUCCESS_UNLOCK); + FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); + String formId = Utils.getParentForm(fc, event.getComponent()).getClientId(fc); + fc.addMessage(formId + ':' + getPropertiesPanelId(), facesMsg); + + getNode().reset(); + return null; + } + }; + txnHelper.doInTransaction(callback); } catch (Throwable e) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( fc, Repository.ERROR_GENERIC), e.getMessage()), e); } @@ -547,45 +544,45 @@ public class DocumentDetailsBean extends BaseDetailsBean */ public String applyInlineEditable() { - UserTransaction tx = null; - try { - tx = Repository.getUserTransaction(FacesContext.getCurrentInstance()); - tx.begin(); - - // add the inlineeditable aspect to the node - Map props = new HashMap(1, 1.0f); - String contentType = null; - ContentData contentData = (ContentData)getDocument().getProperties().get(ContentModel.PROP_CONTENT); - if (contentData != null) + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance()); + RetryingTransactionCallback callback = new RetryingTransactionCallback() { - contentType = contentData.getMimetype(); - } - if (contentType != null) - { - // set the property to true by default if the filetype is a known content type - if (MimetypeMap.MIMETYPE_HTML.equals(contentType) || - MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(contentType) || - MimetypeMap.MIMETYPE_XML.equals(contentType) || - MimetypeMap.MIMETYPE_TEXT_CSS.equals(contentType) || - MimetypeMap.MIMETYPE_JAVASCRIPT.equals(contentType)) + public Object execute() throws Throwable { - props.put(ApplicationModel.PROP_EDITINLINE, true); + // add the inlineeditable aspect to the node + Map props = new HashMap(1, 1.0f); + String contentType = null; + ContentData contentData = (ContentData)getDocument().getProperties().get(ContentModel.PROP_CONTENT); + if (contentData != null) + { + contentType = contentData.getMimetype(); + } + if (contentType != null) + { + // set the property to true by default if the filetype is a known content type + if (MimetypeMap.MIMETYPE_HTML.equals(contentType) || + MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(contentType) || + MimetypeMap.MIMETYPE_XML.equals(contentType) || + MimetypeMap.MIMETYPE_TEXT_CSS.equals(contentType) || + MimetypeMap.MIMETYPE_JAVASCRIPT.equals(contentType)) + { + props.put(ApplicationModel.PROP_EDITINLINE, true); + } + } + nodeService.addAspect(getDocument().getNodeRef(), ApplicationModel.ASPECT_INLINEEDITABLE, props); + + return null; } - } - this.nodeService.addAspect(getDocument().getNodeRef(), ApplicationModel.ASPECT_INLINEEDITABLE, props); - - // commit the transaction - tx.commit(); + }; + txnHelper.doInTransaction(callback); // reset the state of the current document getDocument().reset(); } catch (Throwable e) { - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format(Application.getMessage( FacesContext.getCurrentInstance(), MSG_ERROR_ASPECT_INLINEEDITABLE), e.getMessage()), e); } diff --git a/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java b/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java index c59ee71b40..66c2007577 100644 --- a/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java +++ b/source/java/org/alfresco/web/bean/dialog/BaseDialogBean.java @@ -26,16 +26,15 @@ package org.alfresco.web.bean.dialog; import java.text.MessageFormat; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import javax.faces.context.FacesContext; -import javax.transaction.UserTransaction; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; @@ -96,26 +95,29 @@ public abstract class BaseDialogBean implements IDialogBean public String finish() { - String outcome = getDefaultFinishOutcome(); + final FacesContext context = FacesContext.getCurrentInstance(); + final String defaultOutcome = getDefaultFinishOutcome(); + String outcome = null; // check the isFinished flag to stop the finish button // being pressed multiple times if (this.isFinished == false) { this.isFinished = true; - UserTransaction tx = null; + RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(context); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public String execute() throws Throwable + { + // call the actual implementation + return finishImpl(context, defaultOutcome); + } + }; try { - FacesContext context = FacesContext.getCurrentInstance(); - tx = Repository.getUserTransaction(context); - tx.begin(); - - // call the actual implementation - outcome = finishImpl(context, outcome); - - // persist the changes - tx.commit(); + // Execute + outcome = txnHelper.doInTransaction(callback); // allow any subclasses to perform post commit processing // i.e. resetting state or setting status messages @@ -126,8 +128,6 @@ public abstract class BaseDialogBean implements IDialogBean // reset the flag so we can re-attempt the operation isFinished = false; - // rollback the transaction - try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(formatErrorMessage(e), e); outcome = getErrorOutcome(e); } diff --git a/source/java/org/alfresco/web/bean/repository/Repository.java b/source/java/org/alfresco/web/bean/repository/Repository.java index 6133efb50f..56a94bccb6 100644 --- a/source/java/org/alfresco/web/bean/repository/Repository.java +++ b/source/java/org/alfresco/web/bean/repository/Repository.java @@ -39,6 +39,7 @@ import org.alfresco.repo.configuration.ConfigurableService; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.metadata.MetadataExtracter; import org.alfresco.repo.content.metadata.MetadataExtracterRegistry; +import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockStatus; @@ -376,6 +377,9 @@ public final class Repository * @param context FacesContext * * @return UserTransaction + * + * @deprecated + * @see #getRetryingTransactionHelper(FacesContext) */ public static UserTransaction getUserTransaction(FacesContext context) { @@ -383,6 +387,18 @@ public final class Repository return transactionService.getUserTransaction(); } + /** + * Returns the transaction helper that executes a unit of work. + * + * @param context FacesContext + * @return Returns the transaction helper + */ + public static RetryingTransactionHelper getRetryingTransactionHelper(FacesContext context) + { + TransactionService transactionService = getServiceRegistry(context).getTransactionService(); + return transactionService.getRetryingTransactionHelper(); + } + /** * Return a UserTransaction instance *