mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.1 to HEAD
13033: Back end support for ETHREEOH-1179 13038: JAWS-436 - refactor WCM submit dialog to use WCM sandbox service + update unit tests 13046: Merged V3.0 to V3.1 13043: Merged V2.2 to V3.0 13016: Fix for ETWOTWO-1088 (reset layer using flatten rather than delete & add, users can flatten in stores they own but not delete) 13049: Build/test fix (WCM AssetTest) 13057: Merged V2.1-A to V3.1 8770: Added Flex SDK module 8771: Added Flex SDK binary (swc) DH: I'm not sure about the svn:eol-style property appearing here. SVN Clients? 13059: Added 'AIX' as a platform type, from Adobe V2.1A, missed checkin. 13060: [no comments] 13061: [no comments] 13063: [no comments] 13064: [no comments] 13066: [no comments] 13067: Add NodeService.getChildrenByName 13072: Added new NodeService.getChildrenByName() method to public-services-security-context. ___________________________________________________________________ Modified: svn:mergeinfo Merged /alfresco/BRANCHES/V3.0:r13043 Merged /alfresco/BRANCHES/V2.2:r13016 Merged /alfresco/BRANCHES/V3.1:r13033,13038,13046,13049,13057,13059-13061,13063-13064,13066-13067,13072 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13552 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -42,31 +42,22 @@ import javax.transaction.UserTransaction;
|
||||
import org.alfresco.config.JNDIConstants;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.WCMAppModel;
|
||||
import org.alfresco.model.WCMWorkflowModel;
|
||||
import org.alfresco.repo.avm.AVMNodeConverter;
|
||||
import org.alfresco.repo.domain.PropertyValue;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.repo.web.scripts.FileTypeImageUtils;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
|
||||
import org.alfresco.service.cmr.avm.AVMService;
|
||||
import org.alfresco.service.cmr.avmsync.AVMDifference;
|
||||
import org.alfresco.service.cmr.avmsync.AVMSyncService;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.ISO8601DateFormat;
|
||||
import org.alfresco.util.NameMatcher;
|
||||
import org.alfresco.wcm.sandbox.SandboxFactory;
|
||||
import org.alfresco.wcm.sandbox.SandboxInfo;
|
||||
import org.alfresco.wcm.sandbox.SandboxService;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.app.servlet.DownloadContentServlet;
|
||||
@@ -97,8 +88,6 @@ public class SubmitDialog extends BaseDialogBean
|
||||
private static final String MSG_DELETED_ITEM = "avm_node_deleted";
|
||||
private static final String MSG_ERR_WORKFLOW_CONFIG = "submit_workflow_config_error";
|
||||
|
||||
private static final String WORKFLOW_SUBMITDIRECT = "jbpm$wcmwf:submitdirect";
|
||||
|
||||
private String comment;
|
||||
private String label;
|
||||
private String[] workflowSelectedValue;
|
||||
@@ -115,19 +104,6 @@ public class SubmitDialog extends BaseDialogBean
|
||||
private Map<String, Date> expirationDates;
|
||||
private List<UIListItem> workflowItems;
|
||||
private Map<QName, Serializable> workflowParams;
|
||||
private SandboxInfo sandboxInfo;
|
||||
private List<String> srcPaths;
|
||||
|
||||
// The virtualization server might need to be notified
|
||||
// because one or more of the files submitted could alter
|
||||
// the behavior the virtual webapp in the target of the submit.
|
||||
// For example, the user might be submitting a new jar or web.xml file.
|
||||
//
|
||||
// This must take place after the transaction has been completed;
|
||||
// therefore, a variable is needed to store the path to the
|
||||
// updated webapp so it can happen in doPostCommitProcessing.
|
||||
private String virtUpdatePath;
|
||||
|
||||
|
||||
protected AVMBrowseBean avmBrowseBean;
|
||||
|
||||
@@ -294,8 +270,6 @@ public class SubmitDialog extends BaseDialogBean
|
||||
this.validateLinks = this.avmBrowseBean.getLinkValidationEnabled();
|
||||
this.autoDeploy = false;
|
||||
this.workflowParams = null;
|
||||
this.sandboxInfo = null;
|
||||
this.virtUpdatePath = null;
|
||||
|
||||
// determine if the dialog has been started from a workflow
|
||||
this.loadSelectedNodesFromBrowseBean = Boolean.valueOf(this.parameters.get(PARAM_LOAD_SELECTED_NODES_FROM_BROWSE_BEAN));
|
||||
@@ -339,7 +313,51 @@ public class SubmitDialog extends BaseDialogBean
|
||||
try
|
||||
{
|
||||
// note: always submit via workflow (always defaults to direct submit workflow)
|
||||
outcome = submitViaWorkflow(context);
|
||||
//outcome = submitViaWorkflow(context);
|
||||
|
||||
String workflowName = null;
|
||||
if ((this.workflowSelectedValue != null) && (this.workflowSelectedValue.length > 0))
|
||||
{
|
||||
// get the defaults from the workflow configuration attached to the selected workflow
|
||||
workflowName = this.workflowSelectedValue[0];
|
||||
for (FormWorkflowWrapper wrapper : this.workflows)
|
||||
{
|
||||
if (wrapper.name.equals(workflowName))
|
||||
{
|
||||
this.workflowParams = wrapper.params;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.workflowParams == null)
|
||||
{
|
||||
// create error msg for display in dialog - the user must configure the workflow params
|
||||
Utils.addErrorMessage(Application.getMessage(context, MSG_ERR_WORKFLOW_CONFIG));
|
||||
return outcome;
|
||||
}
|
||||
}
|
||||
|
||||
List<ItemWrapper> items = getSubmitItems();
|
||||
|
||||
List<String> relativePaths = new ArrayList<String>(items.size());
|
||||
|
||||
for (ItemWrapper wrapper : items)
|
||||
{
|
||||
relativePaths.add(AVMUtil.getStoreRelativePath(wrapper.getDescriptor().getPath()));
|
||||
}
|
||||
|
||||
String sbStoreId = this.avmBrowseBean.getSandbox();
|
||||
|
||||
String submitLabel = this.label;
|
||||
String submitComment = this.comment;
|
||||
|
||||
// note: always submit via workflow (if no workflow selected, then defaults to direct submit workflow)
|
||||
getSandboxService().submitListAssets(sbStoreId, relativePaths,
|
||||
workflowName, workflowParams,
|
||||
submitLabel, submitComment,
|
||||
expirationDates, launchDate, validateLinks, autoDeploy);
|
||||
|
||||
// if we get this far return the default outcome
|
||||
outcome = this.getDefaultFinishOutcome();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -350,286 +368,6 @@ public class SubmitDialog extends BaseDialogBean
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the selected items via the configured workflow.
|
||||
* <p>
|
||||
* This method uses 2 separate transactions to perform the submit.
|
||||
* The first one creates the workflow sandbox. The virtualisation
|
||||
* server is then informed of the new stores. The second
|
||||
* transaction then starts the appropriate workflow. This approach
|
||||
* is needed to allow link validation to be performed on the
|
||||
* workflow sandbox.
|
||||
* </p>
|
||||
*
|
||||
* @param context Faces context
|
||||
* @return The outcome to use
|
||||
*/
|
||||
protected String submitViaWorkflow(final FacesContext context)
|
||||
{
|
||||
String outcome = null;
|
||||
|
||||
RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(context);
|
||||
RetryingTransactionCallback<String> sandboxCallback = new RetryingTransactionCallback<String>()
|
||||
{
|
||||
public String execute() throws Throwable
|
||||
{
|
||||
// call the actual implementation
|
||||
createWorkflowSandbox(context);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
RetryingTransactionCallback<String> workflowCallback = new RetryingTransactionCallback<String>()
|
||||
{
|
||||
public String execute() throws Throwable
|
||||
{
|
||||
// call the actual implementation
|
||||
startWorkflow();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// create the workflow sandbox firstly
|
||||
txnHelper.doInTransaction(sandboxCallback, false, true);
|
||||
|
||||
if (this.sandboxInfo != null)
|
||||
{
|
||||
// inform the virtualisation server if the workflow sandbox was created
|
||||
if (this.virtUpdatePath != null)
|
||||
{
|
||||
AVMUtil.updateVServerWebapp(this.virtUpdatePath, true);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// start the workflow
|
||||
txnHelper.doInTransaction(workflowCallback, false, true);
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
cleanupWorkflowSandbox(context);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// if we get this far return the default outcome
|
||||
outcome = this.getDefaultFinishOutcome();
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
Utils.addErrorMessage(formatErrorMessage(e), e);
|
||||
outcome = getErrorOutcome(e);
|
||||
}
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a workflow sandbox for all the submitted items
|
||||
*
|
||||
* @param context Faces context
|
||||
*/
|
||||
protected void createWorkflowSandbox(FacesContext context)
|
||||
{
|
||||
if (this.workflowSelectedValue != null && this.workflowSelectedValue.length > 0)
|
||||
{
|
||||
// get the defaults from the workflow configuration attached to the selected workflow
|
||||
String workflowName = this.workflowSelectedValue[0];
|
||||
for (FormWorkflowWrapper wrapper : this.workflows)
|
||||
{
|
||||
if (wrapper.name.equals(workflowName))
|
||||
{
|
||||
this.workflowParams = wrapper.params;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.workflowParams == null)
|
||||
{
|
||||
// create error msg for display in dialog - the user must configure the workflow params
|
||||
Utils.addErrorMessage(Application.getMessage(context, MSG_ERR_WORKFLOW_CONFIG));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create workflow sandbox for workflow package
|
||||
this.sandboxInfo = sandboxFactory.createWorkflowSandbox(this.avmBrowseBean.getStagingStore());
|
||||
}
|
||||
else
|
||||
{
|
||||
// default to direct submit workflow
|
||||
this.workflowSelectedValue = new String[] { WORKFLOW_SUBMITDIRECT };
|
||||
this.workflowParams = new HashMap<QName, Serializable>();
|
||||
|
||||
// NOTE: read only workflow sandbox is lighter to construct than full workflow sandbox
|
||||
this.sandboxInfo = sandboxFactory.createReadOnlyWorkflowSandbox(this.avmBrowseBean.getStagingStore());
|
||||
}
|
||||
|
||||
// create container for our avm workflow package
|
||||
final List<ItemWrapper> items = this.getSubmitItems();
|
||||
this.srcPaths = new ArrayList<String>(items.size());
|
||||
|
||||
for (ItemWrapper wrapper : items)
|
||||
{
|
||||
// Example srcPath:
|
||||
// mysite--alice:/www/avm_webapps/ROOT/foo.txt
|
||||
String srcPath = wrapper.getDescriptor().getPath();
|
||||
|
||||
// We *always* want to update virtualization server
|
||||
// when a workflow sandbox is given data in the
|
||||
// context of a submit workflow. Without this,
|
||||
// it would be impossible to see workflow data
|
||||
// in context. The raw operation to create a
|
||||
// workflow sandbox does not notify the virtualization
|
||||
// server that it exists because it's useful to
|
||||
// defer this operation until everything is already
|
||||
// in place; this allows pointlessly fine-grained
|
||||
// notifications to be suppressed (they're expensive).
|
||||
//
|
||||
// Therefore, just derive the name of the webapp
|
||||
// in the workflow sandbox from the 1st item in
|
||||
// the submit list (even if it's not in WEB-INF),
|
||||
// and force the virt server notification after the
|
||||
// transaction has completed via doPostCommitProcessing.
|
||||
if (this.virtUpdatePath == null)
|
||||
{
|
||||
// Example workflow main store name:
|
||||
// mysite--workflow-9161f640-b020-11db-8015-130bf9b5b652
|
||||
String workflowMainStoreName = sandboxInfo.getMainStoreName();
|
||||
|
||||
// The virtUpdatePath looks just like the srcPath
|
||||
// except that it belongs to a the main store of
|
||||
// the workflow sandbox instead of the sandbox
|
||||
// that originated the submit.
|
||||
this.virtUpdatePath =
|
||||
workflowMainStoreName +
|
||||
srcPath.substring(srcPath.indexOf(':'),srcPath.length());
|
||||
}
|
||||
|
||||
// process the expiration date (if any)
|
||||
processExpirationDate(srcPath);
|
||||
|
||||
this.srcPaths.add(srcPath);
|
||||
}
|
||||
|
||||
String workflowMainStoreName = sandboxInfo.getMainStoreName();
|
||||
List<AVMDifference> diffs = new ArrayList<AVMDifference>(srcPaths.size());
|
||||
for (final String srcPath : srcPaths)
|
||||
{
|
||||
diffs.add(new AVMDifference(-1, srcPath, -1,
|
||||
AVMUtil.getCorrespondingPath(srcPath, workflowMainStoreName),
|
||||
AVMDifference.NEWER));
|
||||
}
|
||||
|
||||
// write changes to layer so files are marked as modified
|
||||
getAvmSyncService().update(diffs, null, false, false, false, false, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the configured workflow to allow the submitted items to be link
|
||||
* checked and reviewed.
|
||||
*/
|
||||
protected void startWorkflow()
|
||||
{
|
||||
if (this.workflowParams != null)
|
||||
{
|
||||
// start the workflow to get access to the start task
|
||||
String workflowName = this.workflowSelectedValue[0];
|
||||
WorkflowDefinition wfDef = getWorkflowService().getDefinitionByName(workflowName);
|
||||
WorkflowPath path = getWorkflowService().startWorkflow(wfDef.id, null);
|
||||
if (path != null)
|
||||
{
|
||||
// extract the start task
|
||||
List<WorkflowTask> tasks = getWorkflowService().getTasksForWorkflowPath(path.id);
|
||||
if (tasks.size() == 1)
|
||||
{
|
||||
WorkflowTask startTask = tasks.get(0);
|
||||
|
||||
if (startTask.state == WorkflowTaskState.IN_PROGRESS)
|
||||
{
|
||||
final NodeRef workflowPackage =
|
||||
AVMWorkflowUtil.createWorkflowPackage(this.srcPaths, sandboxInfo, path);
|
||||
|
||||
this.workflowParams.put(WorkflowModel.ASSOC_PACKAGE, workflowPackage);
|
||||
|
||||
// add submission parameters
|
||||
this.workflowParams.put(WorkflowModel.PROP_WORKFLOW_DESCRIPTION, getComment());
|
||||
this.workflowParams.put(WCMWorkflowModel.PROP_LABEL, getLabel());
|
||||
this.workflowParams.put(WCMWorkflowModel.PROP_FROM_PATH,
|
||||
AVMUtil.buildStoreRootPath(this.avmBrowseBean.getSandbox()));
|
||||
this.workflowParams.put(WCMWorkflowModel.PROP_LAUNCH_DATE, this.launchDate);
|
||||
this.workflowParams.put(WCMWorkflowModel.PROP_VALIDATE_LINKS,
|
||||
new Boolean(this.validateLinks));
|
||||
this.workflowParams.put(WCMWorkflowModel.PROP_AUTO_DEPLOY,
|
||||
new Boolean(this.autoDeploy));
|
||||
this.workflowParams.put(WCMWorkflowModel.PROP_WEBAPP,
|
||||
this.avmBrowseBean.getWebapp());
|
||||
this.workflowParams.put(WCMWorkflowModel.ASSOC_WEBPROJECT,
|
||||
this.avmBrowseBean.getWebsite().getNodeRef());
|
||||
|
||||
// update start task with submit parameters
|
||||
getWorkflowService().updateTask(startTask.id, this.workflowParams, null, null);
|
||||
|
||||
// end the start task to trigger the first 'proper' task in the workflow
|
||||
getWorkflowService().endTask(startTask.id, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the workflow sandbox created by the first transaction. This
|
||||
* action is itself preformed in a separate transaction.
|
||||
*
|
||||
* @param context Faces context
|
||||
*/
|
||||
protected void cleanupWorkflowSandbox(FacesContext context)
|
||||
{
|
||||
RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(context);
|
||||
RetryingTransactionCallback<String> callback = new RetryingTransactionCallback<String>()
|
||||
{
|
||||
public String execute() throws Throwable
|
||||
{
|
||||
// call the actual implementation
|
||||
cleanupWorkflowSandboxImpl();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// Execute the cleanup handler
|
||||
txnHelper.doInTransaction(callback);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// not much we can do now, just log the error to inform admins
|
||||
logger.error("Failed to cleanup workflow sandbox after workflow failure", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual deletion of stores in the workflow sandbox.
|
||||
*/
|
||||
protected void cleanupWorkflowSandboxImpl()
|
||||
{
|
||||
if (this.sandboxInfo != null)
|
||||
{
|
||||
String mainWorkflowStore = this.sandboxInfo.getMainStoreName();
|
||||
Map<QName, PropertyValue> matches = getAvmService().queryStorePropertyKey(mainWorkflowStore,
|
||||
QName.createQName(null, ".sandbox-id%"));
|
||||
QName sandboxID = matches.keySet().iterator().next();
|
||||
// Get all the stores in the sandbox.
|
||||
Map<String, Map<QName, PropertyValue>> stores = getAvmService().queryStoresPropertyKeys(sandboxID);
|
||||
for (String storeName : stores.keySet())
|
||||
{
|
||||
getAvmService().purgeStore(storeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.web.bean.dialog.BaseDialogBean#getFinishButtonDisabled()
|
||||
*/
|
||||
@@ -1057,36 +795,7 @@ public class SubmitDialog extends BaseDialogBean
|
||||
throw (RuntimeException)e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the expiration date for the given source path
|
||||
*
|
||||
* @param srcPath The path to set the expiration date for
|
||||
*/
|
||||
private void processExpirationDate(String srcPath)
|
||||
{
|
||||
// if an expiration date has been set for this item we need to
|
||||
// add the expires aspect and the date supplied
|
||||
Date expirationDate = this.expirationDates.get(srcPath);
|
||||
if (expirationDate == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// make sure the aspect is present
|
||||
if (getAvmService().hasAspect(-1, srcPath, WCMAppModel.ASPECT_EXPIRES) == false)
|
||||
{
|
||||
getAvmService().addAspect(srcPath, WCMAppModel.ASPECT_EXPIRES);
|
||||
}
|
||||
|
||||
// set the expiration date
|
||||
getAvmService().setNodeProperty(srcPath, WCMAppModel.PROP_EXPIRATIONDATE,
|
||||
new PropertyValue(DataTypeDefinition.DATETIME, expirationDate));
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Set expiration date of " + expirationDate +
|
||||
" for " + srcPath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Action method to setup a workflow for dialog context for the current row
|
||||
*/
|
||||
|
Reference in New Issue
Block a user