mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merge from HEAD to WCM-DEV2.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3659 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
667
source/java/org/alfresco/web/bean/workflow/ManageTaskDialog.java
Normal file
667
source/java/org/alfresco/web/bean/workflow/ManageTaskDialog.java
Normal file
@@ -0,0 +1,667 @@
|
||||
package org.alfresco.web.bean.workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.event.ActionEvent;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowInstance;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTransition;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.web.app.AlfrescoNavigationHandler;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.bean.dialog.BaseDialogBean;
|
||||
import org.alfresco.web.bean.repository.MapNode;
|
||||
import org.alfresco.web.bean.repository.Node;
|
||||
import org.alfresco.web.bean.repository.NodePropertyResolver;
|
||||
import org.alfresco.web.bean.repository.Repository;
|
||||
import org.alfresco.web.bean.repository.TransientNode;
|
||||
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.component.UIActionLink;
|
||||
import org.alfresco.web.ui.common.component.data.UIRichList;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Bean implementation for the "Manage Task" dialog.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class ManageTaskDialog extends BaseDialogBean
|
||||
{
|
||||
protected WorkflowService workflowService;
|
||||
protected Node taskNode;
|
||||
protected WorkflowTask task;
|
||||
protected WorkflowInstance workflowInstance;
|
||||
protected WorkflowTransition[] transitions;
|
||||
protected NodeRef workflowPackage;
|
||||
protected List<Node> resources;
|
||||
protected TaskCompleteResolver completeResolver = new TaskCompleteResolver();
|
||||
protected UIRichList packageItemsRichList;
|
||||
protected List<String> packageItemsToAdd;
|
||||
protected List<String> packageItemsToRemove;
|
||||
protected String[] itemsToAdd;
|
||||
protected boolean isItemBeingAdded = false;
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected static final String ID_PREFIX = "transition_";
|
||||
protected static final String CLIENT_ID_PREFIX = AlfrescoNavigationHandler.DIALOG_PREFIX + ID_PREFIX;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Dialog implementation
|
||||
|
||||
@Override
|
||||
public void init(Map<String, String> parameters)
|
||||
{
|
||||
super.init(parameters);
|
||||
|
||||
// reset variables
|
||||
this.task = null;
|
||||
this.taskNode = null;
|
||||
this.workflowInstance = null;
|
||||
this.transitions = null;
|
||||
this.workflowPackage = null;
|
||||
this.resources = null;
|
||||
this.itemsToAdd = null;
|
||||
this.packageItemsToAdd = null;
|
||||
this.packageItemsToRemove = null;
|
||||
this.isItemBeingAdded = false;
|
||||
if (this.packageItemsRichList != null)
|
||||
{
|
||||
this.packageItemsRichList.setValue(null);
|
||||
this.packageItemsRichList = null;
|
||||
}
|
||||
|
||||
// get the task details
|
||||
String taskId = this.parameters.get("id");
|
||||
this.task = this.workflowService.getTaskById(taskId);
|
||||
|
||||
if (this.task != null)
|
||||
{
|
||||
// setup a transient node to represent the task we're managing
|
||||
WorkflowTaskDefinition taskDef = this.task.definition;
|
||||
this.taskNode = new TransientNode(taskDef.metadata.getName(),
|
||||
"task_" + System.currentTimeMillis(), this.task.properties);
|
||||
|
||||
// get access to the workflow instance for the task
|
||||
this.workflowInstance = this.task.path.instance;
|
||||
|
||||
// setup the workflow package for the task
|
||||
Serializable obj = this.task.properties.get(WorkflowModel.ASSOC_PACKAGE);
|
||||
// TODO: remove this workaroud where JBPM may return a String and not the NodeRef
|
||||
if (obj instanceof NodeRef)
|
||||
{
|
||||
this.workflowPackage = (NodeRef)obj;
|
||||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
this.workflowPackage = new NodeRef((String)obj);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Task: " + this.task);
|
||||
logger.debug("Trasient node: " + this.taskNode);
|
||||
logger.debug("Workflow package: " + this.workflowPackage );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restored()
|
||||
{
|
||||
// reset the workflow package rich list so everything gets re-evaluated
|
||||
if (this.packageItemsRichList != null)
|
||||
{
|
||||
this.packageItemsRichList.setValue(null);
|
||||
this.packageItemsRichList = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String finishImpl(FacesContext context, String outcome)
|
||||
throws Exception
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Saving task: " + this.task.id);
|
||||
|
||||
// prepare the edited parameters for saving
|
||||
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.taskNode);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Saving task with parameters: " + params);
|
||||
|
||||
// remove any items the user selected to remove
|
||||
if (this.workflowPackage != null && this.packageItemsToRemove != null &&
|
||||
this.packageItemsToRemove.size() > 0)
|
||||
{
|
||||
for (String removedItem : this.packageItemsToRemove)
|
||||
{
|
||||
this.nodeService.removeChild(this.workflowPackage, new NodeRef(removedItem));
|
||||
}
|
||||
}
|
||||
|
||||
// add any items the user selected to add
|
||||
if (this.workflowPackage != null && this.packageItemsToAdd != null &&
|
||||
this.packageItemsToAdd.size() > 0)
|
||||
{
|
||||
for (String addedItem : this.packageItemsToAdd)
|
||||
{
|
||||
NodeRef addedNodeRef = new NodeRef(addedItem);
|
||||
this.nodeService.addChild(this.workflowPackage, addedNodeRef,
|
||||
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
QName.createValidLocalName((String)this.nodeService.getProperty(
|
||||
addedNodeRef, ContentModel.PROP_NAME))));
|
||||
}
|
||||
}
|
||||
|
||||
// update the task with the updated parameters
|
||||
this.workflowService.updateTask(this.task.id, params, null, null);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DialogButtonConfig> getAdditionalButtons()
|
||||
{
|
||||
List<DialogButtonConfig> buttons = null;
|
||||
|
||||
if (this.task != null)
|
||||
{
|
||||
// get the transitions available from this task and
|
||||
// show them in the dialog as additional buttons
|
||||
this.transitions = this.task.path.node.transitions;
|
||||
|
||||
if (this.transitions != null)
|
||||
{
|
||||
buttons = new ArrayList<DialogButtonConfig>(this.transitions.length);
|
||||
|
||||
for (WorkflowTransition trans : this.transitions)
|
||||
{
|
||||
buttons.add(new DialogButtonConfig(ID_PREFIX + trans.title, trans.title, null,
|
||||
"#{DialogManager.bean.transition}", "false", null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFinishButtonLabel()
|
||||
{
|
||||
return Application.getMessage(FacesContext.getCurrentInstance(), "save");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFinishButtonDisabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle()
|
||||
{
|
||||
String titleStart = Application.getMessage(FacesContext.getCurrentInstance(), "manage_task_title");
|
||||
|
||||
return titleStart + ": " + this.task.title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return this.task.description;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Event handlers
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String transition()
|
||||
{
|
||||
String outcome = getDefaultFinishOutcome();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Transitioning task: " + this.task.id);
|
||||
|
||||
// to find out which transition button was pressed we need
|
||||
// to look for the button's id in the request parameters,
|
||||
// the first non-null result is the button that was pressed.
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
Map reqParams = context.getExternalContext().getRequestParameterMap();
|
||||
|
||||
String selectedTransition = null;
|
||||
for (WorkflowTransition trans : this.transitions)
|
||||
{
|
||||
Object result = reqParams.get(CLIENT_ID_PREFIX + trans.title);
|
||||
if (result != null)
|
||||
{
|
||||
// this was the button that was pressed
|
||||
selectedTransition = trans.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedTransition != null)
|
||||
{
|
||||
UserTransaction tx = null;
|
||||
|
||||
try
|
||||
{
|
||||
tx = Repository.getUserTransaction(context);
|
||||
tx.begin();
|
||||
|
||||
// prepare the edited parameters for saving
|
||||
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.taskNode);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Transitioning task with parameters: " + params);
|
||||
|
||||
// update the task with the updated parameters
|
||||
this.workflowService.updateTask(this.task.id, params, null, null);
|
||||
|
||||
// signal the selected transition to the workflow task
|
||||
this.workflowService.endTask(this.task.id, selectedTransition);
|
||||
|
||||
// commit the changes
|
||||
tx.commit();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Ended task with transition: " + selectedTransition);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// rollback the transaction
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
|
||||
Utils.addErrorMessage(formatErrorMessage(e), e);
|
||||
outcome = this.getErrorOutcome(e);
|
||||
}
|
||||
}
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the dialog to allow the user to add an item to the workflow package
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
public void prepareForAdd(ActionEvent event)
|
||||
{
|
||||
this.isItemBeingAdded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the adding of an item to the workflow package
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
public void cancelAddPackageItems(ActionEvent event)
|
||||
{
|
||||
this.isItemBeingAdded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item to the workflow package
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
public void addPackageItems(ActionEvent event)
|
||||
{
|
||||
if (this.itemsToAdd != null)
|
||||
{
|
||||
if (this.packageItemsToAdd == null)
|
||||
{
|
||||
// create the list of items to add if necessary
|
||||
this.packageItemsToAdd = new ArrayList<String>(this.itemsToAdd.length);
|
||||
}
|
||||
|
||||
for (String item : this.itemsToAdd)
|
||||
{
|
||||
// if this item is in the remove list it means it was there originally
|
||||
// and has now been re-added, as a result we don't need to do anything
|
||||
// to the original workflow package, therefore remove from the remove list
|
||||
if (this.packageItemsToRemove != null && this.packageItemsToRemove.contains(item))
|
||||
{
|
||||
this.packageItemsToRemove.remove(item);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Removed item from the removed list: " + item);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.packageItemsToAdd.add(item);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Added item to the added list: " + item);
|
||||
}
|
||||
}
|
||||
|
||||
// reset the rich list so it re-renders
|
||||
this.packageItemsRichList.setValue(null);
|
||||
}
|
||||
|
||||
this.isItemBeingAdded = false;
|
||||
this.itemsToAdd = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from the workflow package
|
||||
*
|
||||
* @param event The event containing a reference to the item to remove
|
||||
*/
|
||||
public void removePackageItem(ActionEvent event)
|
||||
{
|
||||
UIActionLink link = (UIActionLink)event.getComponent();
|
||||
Map<String, String> params = link.getParameterMap();
|
||||
String nodeRef = new NodeRef(Repository.getStoreRef(), params.get("id")).toString();
|
||||
|
||||
if (this.packageItemsToAdd != null && this.packageItemsToAdd.contains(nodeRef))
|
||||
{
|
||||
// remove the item from the added list if it was added in this dialog session
|
||||
this.packageItemsToAdd.remove(nodeRef);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Removed item from the added list: " + nodeRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the node to the list of items to remove
|
||||
if (this.packageItemsToRemove == null)
|
||||
{
|
||||
this.packageItemsToRemove = new ArrayList<String>(1);
|
||||
}
|
||||
|
||||
this.packageItemsToRemove.add(nodeRef);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Added item to the removed list: " + nodeRef);
|
||||
}
|
||||
|
||||
// reset the rich list so it re-renders
|
||||
this.packageItemsRichList.setValue(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the complete flag for a workflow package item
|
||||
*
|
||||
* @param event The event containing a reference to the item to toggle the status for
|
||||
*/
|
||||
public void togglePackageItemComplete(ActionEvent event)
|
||||
{
|
||||
// TODO: implement this!
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Bean Getters and Setters
|
||||
|
||||
/**
|
||||
* Returns a String array of NodeRef's that are being added to the workflow package
|
||||
*
|
||||
* @return String array of NodeRef's
|
||||
*/
|
||||
public String[] getItemsToAdd()
|
||||
{
|
||||
return this.itemsToAdd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the NodeRef's to add as items to the workflow package
|
||||
*
|
||||
* @param itemsToAdd NodeRef's to add to the workflow package
|
||||
*/
|
||||
public void setItemsToAdd(String[] itemsToAdd)
|
||||
{
|
||||
this.itemsToAdd = itemsToAdd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an item is currently being added to the workflow package
|
||||
*
|
||||
* @return true if an item is being added
|
||||
*/
|
||||
public boolean isItemBeingAdded()
|
||||
{
|
||||
return this.isItemBeingAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rich list being used for the workflow package items
|
||||
*
|
||||
* @param richList The rich list instance
|
||||
*/
|
||||
public void setPackageItemsRichList(UIRichList richList)
|
||||
{
|
||||
this.packageItemsRichList = richList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rich list being used for the workflow package items
|
||||
*
|
||||
* @return The rich list instance
|
||||
*/
|
||||
public UIRichList getPackageItemsRichList()
|
||||
{
|
||||
return this.packageItemsRichList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Node representing the task
|
||||
*
|
||||
* @return The node
|
||||
*/
|
||||
public Node getTaskNode()
|
||||
{
|
||||
return this.taskNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the WorkflowInstance that the current task belongs to
|
||||
*
|
||||
* @return The workflow instance
|
||||
*/
|
||||
public WorkflowInstance getWorkflowInstance()
|
||||
{
|
||||
return this.workflowInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action group the current task uses for the workflow package
|
||||
*
|
||||
* @return action group id
|
||||
*/
|
||||
public String getPackageActionGroup()
|
||||
{
|
||||
return (String)this.task.properties.get(
|
||||
WorkflowModel.PROP_PACKAGE_ACTION_GROUP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action group the current task uses for each workflow package item
|
||||
*
|
||||
* @return action group id
|
||||
*/
|
||||
public String getPackageItemActionGroup()
|
||||
{
|
||||
return (String)this.task.properties.get(
|
||||
WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of resources associated with this task
|
||||
* i.e. the children of the workflow package
|
||||
*
|
||||
* @return The list of nodes
|
||||
*/
|
||||
public List<Node> getResources()
|
||||
{
|
||||
this.resources = new ArrayList<Node>(4);
|
||||
|
||||
if (this.workflowPackage != null)
|
||||
{
|
||||
UserTransaction tx = null;
|
||||
try
|
||||
{
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
tx = Repository.getUserTransaction(context, true);
|
||||
tx.begin();
|
||||
|
||||
// get existing workflow package items
|
||||
List<ChildAssociationRef> childRefs = this.nodeService.getChildAssocs(
|
||||
this.workflowPackage, ContentModel.ASSOC_CONTAINS,
|
||||
RegexQNamePattern.MATCH_ALL);
|
||||
|
||||
for (ChildAssociationRef ref: childRefs)
|
||||
{
|
||||
// create our Node representation from the NodeRef
|
||||
NodeRef nodeRef = ref.getChildRef();
|
||||
|
||||
if (this.nodeService.exists(nodeRef))
|
||||
{
|
||||
// find it's type so we can see if it's a node we are interested in
|
||||
QName type = this.nodeService.getType(nodeRef);
|
||||
|
||||
// make sure the type is defined in the data dictionary
|
||||
TypeDefinition typeDef = this.dictionaryService.getType(type);
|
||||
|
||||
if (typeDef != null)
|
||||
{
|
||||
// look for content nodes or links to content
|
||||
// NOTE: folders within workflow packages are ignored for now
|
||||
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
|
||||
ContentModel.TYPE_FILELINK.equals(type))
|
||||
{
|
||||
// if the node is not in the removed list then add create the
|
||||
// client side representation and add to the list
|
||||
if (this.packageItemsToRemove == null ||
|
||||
this.packageItemsToRemove.contains(nodeRef.toString()) == false)
|
||||
{
|
||||
createAndAddNode(nodeRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
|
||||
}
|
||||
}
|
||||
|
||||
// now iterate through the items to add list and add them to the list of resources
|
||||
if (this.packageItemsToAdd != null)
|
||||
{
|
||||
for (String newItem : this.packageItemsToAdd)
|
||||
{
|
||||
NodeRef nodeRef = new NodeRef(newItem);
|
||||
if (this.nodeService.exists(nodeRef))
|
||||
{
|
||||
// we know the type is correct as this was added as a result of a query
|
||||
// for all content items so just add the item to the resources list
|
||||
createAndAddNode(nodeRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// commit the transaction
|
||||
tx.commit();
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
|
||||
this.resources = Collections.<Node>emptyList();
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
|
||||
}
|
||||
}
|
||||
else if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Failed to find workflow package for task: " + this.task.id);
|
||||
}
|
||||
|
||||
return this.resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the workflow service to use
|
||||
*
|
||||
* @param workflowService
|
||||
* WorkflowService instance
|
||||
*/
|
||||
public void setWorkflowService(WorkflowService workflowService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helper methods
|
||||
|
||||
protected void createAndAddNode(NodeRef nodeRef)
|
||||
{
|
||||
// create our Node representation
|
||||
MapNode node = new MapNode(nodeRef, this.nodeService, true);
|
||||
this.browseBean.setupCommonBindingProperties(node);
|
||||
|
||||
// add property resolvers to show path information
|
||||
node.addPropertyResolver("path", this.browseBean.resolverPath);
|
||||
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
|
||||
|
||||
// add a property resolver to indicate whether the item has been completed or not
|
||||
// node.addPropertyResolver("completed", this.completeResolver);
|
||||
|
||||
this.resources.add(node);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Inner classes
|
||||
|
||||
/**
|
||||
* Property resolver to determine if the given node has been flagged as complete
|
||||
*/
|
||||
protected class TaskCompleteResolver implements NodePropertyResolver
|
||||
{
|
||||
public Object get(Node node)
|
||||
{
|
||||
String result = Application.getMessage(FacesContext.getCurrentInstance(), "no");
|
||||
|
||||
List<NodeRef> completedItems = (List<NodeRef>)task.properties.get(
|
||||
WorkflowModel.PROP_COMPLETED_ITEMS);
|
||||
|
||||
if (completedItems != null && completedItems.size() > 0 &&
|
||||
completedItems.contains(node.getNodeRef()))
|
||||
{
|
||||
result = Application.getMessage(FacesContext.getCurrentInstance(), "yes");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,476 +0,0 @@
|
||||
package org.alfresco.web.bean.workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.event.ActionEvent;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTransition;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.bean.dialog.BaseDialogBean;
|
||||
import org.alfresco.web.bean.repository.MapNode;
|
||||
import org.alfresco.web.bean.repository.Node;
|
||||
import org.alfresco.web.bean.repository.NodePropertyResolver;
|
||||
import org.alfresco.web.bean.repository.Repository;
|
||||
import org.alfresco.web.bean.repository.TransientNode;
|
||||
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.component.UIActionLink;
|
||||
import org.alfresco.web.ui.common.component.data.UIRichList;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Bean implementation for the "Manage WorkItem" dialog.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class ManageWorkItemDialog extends BaseDialogBean
|
||||
{
|
||||
protected WorkflowService workflowService;
|
||||
protected Node workItemNode;
|
||||
protected WorkflowTask workItem;
|
||||
protected WorkflowTransition[] transitions;
|
||||
protected List<Node> resources;
|
||||
protected WorkItemCompleteResolver completeResolver = new WorkItemCompleteResolver();
|
||||
protected UIRichList packageItemsRichList;
|
||||
|
||||
protected static final String ID_PREFIX = "transition_";
|
||||
protected static final String CLIENT_ID_PREFIX = "dialog:" + ID_PREFIX;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ManageWorkItemDialog.class);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Dialog implementation
|
||||
|
||||
@Override
|
||||
public void init(Map<String, String> parameters)
|
||||
{
|
||||
super.init(parameters);
|
||||
|
||||
String taskId = this.parameters.get("id");
|
||||
this.workItem = this.workflowService.getTaskById(taskId);
|
||||
|
||||
if (this.workItem != null)
|
||||
{
|
||||
// setup a transient node to represent the work item we're managing
|
||||
WorkflowTaskDefinition taskDef = this.workItem.definition;
|
||||
this.workItemNode = new TransientNode(taskDef.metadata.getName(),
|
||||
"task_" + System.currentTimeMillis(), this.workItem.properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String finishImpl(FacesContext context, String outcome)
|
||||
throws Exception
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Saving work item: " + this.workItemNode.getId());
|
||||
|
||||
// prepare the edited parameters for saving
|
||||
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.workItemNode);
|
||||
|
||||
// update the task with the updated parameters
|
||||
this.workflowService.updateTask(this.workItem.id, params, null, null);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DialogButtonConfig> getAdditionalButtons()
|
||||
{
|
||||
List<DialogButtonConfig> buttons = null;
|
||||
|
||||
if (this.workItem != null)
|
||||
{
|
||||
// get the transitions available from this work item and
|
||||
// show them in the dialog as additional buttons
|
||||
this.transitions = this.workItem.path.node.transitions;
|
||||
|
||||
if (this.transitions != null)
|
||||
{
|
||||
buttons = new ArrayList<DialogButtonConfig>(this.transitions.length);
|
||||
|
||||
for (WorkflowTransition trans : this.transitions)
|
||||
{
|
||||
buttons.add(new DialogButtonConfig(ID_PREFIX + trans.title, trans.title, null,
|
||||
"#{DialogManager.bean.transition}", "false", null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFinishButtonLabel()
|
||||
{
|
||||
return Application.getMessage(FacesContext.getCurrentInstance(), "save");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFinishButtonDisabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Event handlers
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String transition()
|
||||
{
|
||||
String outcome = getDefaultFinishOutcome();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Transitioning work item: " + this.workItemNode.getId());
|
||||
|
||||
// to find out which transition button was pressed we need
|
||||
// to look for the button's id in the request parameters,
|
||||
// the first non-null result is the button that was pressed.
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
Map reqParams = context.getExternalContext().getRequestParameterMap();
|
||||
|
||||
String selectedTransition = null;
|
||||
for (WorkflowTransition trans : this.transitions)
|
||||
{
|
||||
Object result = reqParams.get(CLIENT_ID_PREFIX + trans.title);
|
||||
if (result != null)
|
||||
{
|
||||
// this was the button that was pressed
|
||||
selectedTransition = trans.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedTransition != null)
|
||||
{
|
||||
UserTransaction tx = null;
|
||||
|
||||
try
|
||||
{
|
||||
tx = Repository.getUserTransaction(context);
|
||||
tx.begin();
|
||||
|
||||
// prepare the edited parameters for saving
|
||||
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.workItemNode);
|
||||
|
||||
// update the task with the updated parameters
|
||||
this.workflowService.updateTask(this.workItem.id, params, null, null);
|
||||
|
||||
// signal the selected transition to the workflow task
|
||||
this.workflowService.endTask(this.workItem.id, selectedTransition);
|
||||
|
||||
// commit the changes
|
||||
tx.commit();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Ended work item with transition: " + selectedTransition);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// rollback the transaction
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
|
||||
Utils.addErrorMessage(formatErrorMessage(e), e);
|
||||
outcome = this.getErrorOutcome(e);
|
||||
}
|
||||
}
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from the workflow package
|
||||
*
|
||||
* @param event The event containing a reference to the item to remove
|
||||
*/
|
||||
public void removePackageItem(ActionEvent event)
|
||||
{
|
||||
logger.info("remove package item: " + event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the complete flag for a workflow package item
|
||||
*
|
||||
* @param event The event containing a reference to the item to toggle the status for
|
||||
*/
|
||||
public void togglePackageItemComplete(ActionEvent event)
|
||||
{
|
||||
UserTransaction tx = null;
|
||||
try
|
||||
{
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
tx = Repository.getUserTransaction(context);
|
||||
tx.begin();
|
||||
|
||||
UIActionLink link = (UIActionLink)event.getComponent();
|
||||
Map<String, String> params = link.getParameterMap();
|
||||
|
||||
// create the node ref for the item we are toggling
|
||||
NodeRef nodeRef = new NodeRef(Repository.getStoreRef(),
|
||||
(String)params.get("id"));
|
||||
|
||||
// get the existing list of completed items
|
||||
List<NodeRef> completedItems = (List<NodeRef>)this.workItem.properties.get(
|
||||
WorkflowModel.PROP_COMPLETED_ITEMS);
|
||||
|
||||
if (completedItems == null)
|
||||
{
|
||||
// if it doesn't exist yet create the list and add the noderef
|
||||
completedItems = new ArrayList<NodeRef>(1);
|
||||
completedItems.add(nodeRef);
|
||||
this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS,
|
||||
(Serializable)completedItems);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (completedItems.contains(nodeRef))
|
||||
{
|
||||
// the item is already in the list remove it
|
||||
completedItems.remove(nodeRef);
|
||||
|
||||
// NOTE: There is a bug somwehere which causes the list to be
|
||||
// returned as a byte array instead of a list if an empty
|
||||
// list is persisted, therefore if the list is now empty
|
||||
// set the completed items back to null
|
||||
if (completedItems.size() == 0)
|
||||
{
|
||||
this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the noderef is not in the list yet so just add it
|
||||
completedItems.add(nodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
// update the task with the updated parameters
|
||||
this.workflowService.updateTask(this.workItem.id, this.workItem.properties,
|
||||
null, null);
|
||||
|
||||
// commit the transaction
|
||||
tx.commit();
|
||||
|
||||
// reset the rich list if the change was successful
|
||||
this.packageItemsRichList.setValue(null);
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
|
||||
this.resources = Collections.<Node>emptyList();
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Bean Getters and Setters
|
||||
|
||||
/**
|
||||
* Sets the rich list being used for the workflow package items
|
||||
*
|
||||
* @param richList The rich list instance
|
||||
*/
|
||||
public void setPackageItemsRichList(UIRichList richList)
|
||||
{
|
||||
this.packageItemsRichList = richList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rich list being used for the workflow package items
|
||||
*
|
||||
* @return The rich list instance
|
||||
*/
|
||||
public UIRichList getPackageItemsRichList()
|
||||
{
|
||||
return this.packageItemsRichList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Node representing the work item
|
||||
*
|
||||
* @return The node
|
||||
*/
|
||||
public Node getWorkItemNode()
|
||||
{
|
||||
return this.workItemNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action group the current task uses for the workflow package
|
||||
*
|
||||
* @return action group id
|
||||
*/
|
||||
public String getPackageActionGroup()
|
||||
{
|
||||
return (String)this.workItem.properties.get(
|
||||
WorkflowModel.PROP_PACKAGE_ACTION_GROUP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action group the current task uses for each workflow package item
|
||||
*
|
||||
* @return action group id
|
||||
*/
|
||||
public String getPackageItemActionGroup()
|
||||
{
|
||||
return (String)this.workItem.properties.get(
|
||||
WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of resources associated with this work item
|
||||
* i.e. the children of the workflow package
|
||||
*
|
||||
* @return The list of nodes
|
||||
*/
|
||||
public List<Node> getResources()
|
||||
{
|
||||
NodeRef workflowPackage = null;
|
||||
Serializable obj = this.workItem.properties.get(WorkflowModel.ASSOC_PACKAGE);
|
||||
// TODO: remove this workaroud where JBPM may return a String and not the NodeRef
|
||||
if (obj instanceof NodeRef)
|
||||
{
|
||||
workflowPackage = (NodeRef)obj;
|
||||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
workflowPackage = new NodeRef((String)obj);
|
||||
}
|
||||
|
||||
this.resources = new ArrayList<Node>(4);
|
||||
|
||||
if (workflowPackage != null)
|
||||
{
|
||||
UserTransaction tx = null;
|
||||
try
|
||||
{
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
tx = Repository.getUserTransaction(context, true);
|
||||
tx.begin();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Found workflow package for work item '" +
|
||||
this.workItem.id + "': " + workflowPackage );
|
||||
|
||||
List<ChildAssociationRef> childRefs = this.nodeService.getChildAssocs(workflowPackage,
|
||||
ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
|
||||
|
||||
for (ChildAssociationRef ref: childRefs)
|
||||
{
|
||||
// create our Node representation from the NodeRef
|
||||
NodeRef nodeRef = ref.getChildRef();
|
||||
|
||||
if (this.nodeService.exists(nodeRef))
|
||||
{
|
||||
// find it's type so we can see if it's a node we are interested in
|
||||
QName type = this.nodeService.getType(nodeRef);
|
||||
|
||||
// make sure the type is defined in the data dictionary
|
||||
TypeDefinition typeDef = this.dictionaryService.getType(type);
|
||||
|
||||
if (typeDef != null)
|
||||
{
|
||||
// look for content nodes or links to content
|
||||
// NOTE: folders within workflow packages are ignored for now
|
||||
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
|
||||
ContentModel.TYPE_FILELINK.equals(type))
|
||||
{
|
||||
// create our Node representation
|
||||
MapNode node = new MapNode(nodeRef, this.nodeService, true);
|
||||
this.browseBean.setupCommonBindingProperties(node);
|
||||
|
||||
// add property resolvers to show path information
|
||||
node.addPropertyResolver("path", this.browseBean.resolverPath);
|
||||
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
|
||||
|
||||
// add a property resolver to indicate whether the item has been completed or not
|
||||
node.addPropertyResolver("completed", this.completeResolver);
|
||||
|
||||
this.resources.add(node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// commit the transaction
|
||||
tx.commit();
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
|
||||
this.resources = Collections.<Node>emptyList();
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
|
||||
}
|
||||
}
|
||||
else if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Failed to find workflow package for work item: " + this.workItem.id);
|
||||
}
|
||||
|
||||
return this.resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the workflow service to use
|
||||
*
|
||||
* @param workflowService
|
||||
* WorkflowService instance
|
||||
*/
|
||||
public void setWorkflowService(WorkflowService workflowService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helper methods
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Inner classes
|
||||
|
||||
/**
|
||||
* Property resolver to determine if the given node has been flagged as complete
|
||||
*/
|
||||
protected class WorkItemCompleteResolver implements NodePropertyResolver
|
||||
{
|
||||
public Object get(Node node)
|
||||
{
|
||||
String result = Application.getMessage(FacesContext.getCurrentInstance(), "no");
|
||||
|
||||
List<NodeRef> completedItems = (List<NodeRef>)workItem.properties.get(
|
||||
WorkflowModel.PROP_COMPLETED_ITEMS);
|
||||
|
||||
if (completedItems != null && completedItems.size() > 0 &&
|
||||
completedItems.contains(node.getNodeRef()))
|
||||
{
|
||||
result = Application.getMessage(FacesContext.getCurrentInstance(), "yes");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,199 @@
|
||||
package org.alfresco.web.bean.workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.model.SelectItem;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.bean.dialog.BaseDialogBean;
|
||||
import org.alfresco.web.bean.repository.Repository;
|
||||
import org.alfresco.web.ui.common.SortableSelectItem;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.component.UIGenericPicker;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Bean implementation for the "Reassign Task" dialog
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class ReassignTaskDialog extends BaseDialogBean
|
||||
{
|
||||
protected String taskId;
|
||||
|
||||
protected WorkflowService workflowService;
|
||||
protected PersonService personService;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ReassignTaskDialog.class);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Dialog implementation
|
||||
|
||||
@Override
|
||||
public void init(Map<String, String> parameters)
|
||||
{
|
||||
super.init(parameters);
|
||||
|
||||
this.taskId = this.parameters.get("task-id");
|
||||
if (this.taskId == null || this.taskId.length() == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Reassign task dialog called without task id");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String finishImpl(FacesContext context, String outcome)
|
||||
throws Exception
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Reassigning task with id: " + this.taskId);
|
||||
|
||||
UIComponent picker = context.getViewRoot().findComponent("dialog:dialog-body:user-picker");
|
||||
|
||||
if (picker != null && picker instanceof UIGenericPicker)
|
||||
{
|
||||
UIGenericPicker userPicker = (UIGenericPicker)picker;
|
||||
String[] user = userPicker.getSelectedResults();
|
||||
if (user != null && user.length > 0)
|
||||
{
|
||||
// create a map to hold the new owner property then update the task
|
||||
String userName = user[0];
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>(1);
|
||||
params.put(ContentModel.PROP_OWNER, userName);
|
||||
this.workflowService.updateTask(this.taskId, params, null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
logger.warn("Failed to find selected user, reassign was unsuccessful");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
logger.warn("Failed to find user-picker component, reassign was unsuccessful");
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Reassigning task with id: " + this.taskId);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getErrorMessageId()
|
||||
{
|
||||
return "error_reassign_task";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Bean Getters and Setters
|
||||
|
||||
/**
|
||||
* Property accessed by the Generic Picker component.
|
||||
*
|
||||
* @return the array of filter options to show in the users/groups picker
|
||||
*/
|
||||
public SelectItem[] getFilters()
|
||||
{
|
||||
ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
|
||||
return new SelectItem[] {new SelectItem("0", bundle.getString("users"))};
|
||||
}
|
||||
|
||||
/**
|
||||
* Query callback method executed by the Generic Picker component.
|
||||
* This method is part of the contract to the Generic Picker, it is up to the backing bean
|
||||
* to execute whatever query is appropriate and return the results.
|
||||
*
|
||||
* @param filterIndex Index of the filter drop-down selection
|
||||
* @param contains Text from the contains textbox
|
||||
*
|
||||
* @return An array of SelectItem objects containing the results to display in the picker.
|
||||
*/
|
||||
public SelectItem[] pickerCallback(int filterIndex, String contains)
|
||||
{
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
|
||||
SelectItem[] items;
|
||||
|
||||
UserTransaction tx = null;
|
||||
try
|
||||
{
|
||||
tx = Repository.getUserTransaction(context, true);
|
||||
tx.begin();
|
||||
|
||||
// build xpath to match available User/Person objects
|
||||
NodeRef peopleRef = personService.getPeopleContainer();
|
||||
// NOTE: see SearcherComponentTest
|
||||
String xpath = "*[like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "firstName, '%" + contains + "%', false)" +
|
||||
" or " + "like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "lastName, '%" + contains + "%', false)]";
|
||||
|
||||
List<NodeRef> nodes = searchService.selectNodes(
|
||||
peopleRef,
|
||||
xpath,
|
||||
null,
|
||||
this.namespaceService,
|
||||
false);
|
||||
|
||||
items = new SelectItem[nodes.size()];
|
||||
for (int index=0; index<nodes.size(); index++)
|
||||
{
|
||||
NodeRef personRef = nodes.get(index);
|
||||
String firstName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
|
||||
String lastName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
|
||||
String username = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_USERNAME);
|
||||
SelectItem item = new SortableSelectItem(username, firstName + " " + lastName, lastName);
|
||||
items[index] = item;
|
||||
}
|
||||
|
||||
Arrays.sort(items);
|
||||
|
||||
// commit the transaction
|
||||
tx.commit();
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
|
||||
|
||||
items = new SelectItem[0];
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the workflow service to use
|
||||
*
|
||||
* @param workflowService The WorkflowService instance
|
||||
*/
|
||||
public void setWorkflowService(WorkflowService workflowService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permissionService The PermissionService to set.
|
||||
*/
|
||||
public void setPersonService(PersonService personService)
|
||||
{
|
||||
this.personService = personService;
|
||||
}
|
||||
}
|
@@ -1,14 +1,18 @@
|
||||
package org.alfresco.web.bean.workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.event.ActionEvent;
|
||||
import javax.faces.model.SelectItem;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
@@ -23,10 +27,14 @@ import org.alfresco.service.cmr.workflow.WorkflowTaskState;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.bean.repository.MapNode;
|
||||
import org.alfresco.web.bean.repository.Node;
|
||||
import org.alfresco.web.bean.repository.Repository;
|
||||
import org.alfresco.web.bean.repository.TransientNode;
|
||||
import org.alfresco.web.bean.wizard.BaseWizardBean;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.component.UIActionLink;
|
||||
import org.alfresco.web.ui.common.component.data.UIRichList;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -42,6 +50,11 @@ public class StartWorkflowWizard extends BaseWizardBean
|
||||
protected Map<String, WorkflowDefinition> workflows;
|
||||
protected WorkflowService workflowService;
|
||||
protected Node startTaskNode;
|
||||
protected List<Node> resources;
|
||||
protected List<String> packageItemsToAdd;
|
||||
protected UIRichList packageItemsRichList;
|
||||
protected String[] itemsToAdd;
|
||||
protected boolean isItemBeingAdded = false;
|
||||
protected boolean nextButtonDisabled = false;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(StartWorkflowWizard.class);
|
||||
@@ -65,6 +78,43 @@ public class StartWorkflowWizard extends BaseWizardBean
|
||||
}
|
||||
|
||||
this.startTaskNode = null;
|
||||
this.resources = null;
|
||||
this.itemsToAdd = null;
|
||||
this.packageItemsToAdd = new ArrayList<String>();
|
||||
this.isItemBeingAdded = false;
|
||||
if (this.packageItemsRichList != null)
|
||||
{
|
||||
this.packageItemsRichList.setValue(null);
|
||||
this.packageItemsRichList = null;
|
||||
}
|
||||
|
||||
// TODO: Does this need to be in a read-only transaction??
|
||||
|
||||
// add the item the workflow wizard was started on to the list of resources
|
||||
String itemToWorkflowId = this.parameters.get("item-to-workflow");
|
||||
if (itemToWorkflowId != null && itemToWorkflowId.length() > 0)
|
||||
{
|
||||
// create the node ref for the item and determine its type
|
||||
NodeRef itemToWorkflow = new NodeRef(Repository.getStoreRef(), itemToWorkflowId);
|
||||
QName type = this.nodeService.getType(itemToWorkflow);
|
||||
|
||||
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
|
||||
this.dictionaryService.isSubClass(type, ContentModel.TYPE_FILELINK))
|
||||
{
|
||||
this.packageItemsToAdd.add(itemToWorkflow.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restored()
|
||||
{
|
||||
// reset the workflow package rich list so everything gets re-evaluated
|
||||
if (this.packageItemsRichList != null)
|
||||
{
|
||||
this.packageItemsRichList.setValue(null);
|
||||
this.packageItemsRichList = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,26 +127,23 @@ public class StartWorkflowWizard extends BaseWizardBean
|
||||
logger.debug("Starting workflow: " + this.selectedWorkflow);
|
||||
|
||||
// prepare the parameters from the current state of the property sheet
|
||||
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.startTaskNode);
|
||||
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.startTaskNode);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Starting workflow with parameters: " + params);
|
||||
|
||||
// create a workflow package for the attached items and add them
|
||||
String itemToWorkflowId = this.parameters.get("item-to-workflow");
|
||||
if (itemToWorkflowId != null && itemToWorkflowId.length() > 0)
|
||||
if (this.packageItemsToAdd.size() > 0)
|
||||
{
|
||||
// create the node ref for the item and determine its type
|
||||
NodeRef itemToWorkflow = new NodeRef(Repository.getStoreRef(), itemToWorkflowId);
|
||||
QName type = this.nodeService.getType(itemToWorkflow);
|
||||
NodeRef workflowPackage = this.workflowService.createPackage(null);
|
||||
|
||||
NodeRef workflowPackage = null;
|
||||
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
|
||||
this.dictionaryService.isSubClass(type, ContentModel.TYPE_FILELINK))
|
||||
for (String addedItem : this.packageItemsToAdd)
|
||||
{
|
||||
// create a workflow package and add the given item to workflow as a child
|
||||
workflowPackage = this.workflowService.createPackage(null);
|
||||
this.nodeService.addChild(workflowPackage, itemToWorkflow,
|
||||
NodeRef addedNodeRef = new NodeRef(addedItem);
|
||||
this.nodeService.addChild(workflowPackage, addedNodeRef,
|
||||
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
QName.createValidLocalName((String)this.nodeService.getProperty(
|
||||
itemToWorkflow, ContentModel.PROP_NAME))));
|
||||
addedNodeRef, ContentModel.PROP_NAME))));
|
||||
}
|
||||
|
||||
// add the workflow package to the parameter map
|
||||
@@ -175,9 +222,131 @@ public class StartWorkflowWizard extends BaseWizardBean
|
||||
return this.nextButtonDisabled;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Event Handlers
|
||||
|
||||
/**
|
||||
* Prepares the dialog to allow the user to add an item to the workflow package
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
public void prepareForAdd(ActionEvent event)
|
||||
{
|
||||
this.isItemBeingAdded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the adding of an item to the workflow package
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
public void cancelAddPackageItems(ActionEvent event)
|
||||
{
|
||||
this.isItemBeingAdded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds items to the workflow package
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
public void addPackageItems(ActionEvent event)
|
||||
{
|
||||
if (this.itemsToAdd != null)
|
||||
{
|
||||
for (String item : this.itemsToAdd)
|
||||
{
|
||||
this.packageItemsToAdd.add(item);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Added item to the added list: " + item);
|
||||
}
|
||||
|
||||
// reset the rich list so it re-renders
|
||||
this.packageItemsRichList.setValue(null);
|
||||
}
|
||||
|
||||
this.isItemBeingAdded = false;
|
||||
this.itemsToAdd = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from the workflow package
|
||||
*
|
||||
* @param event The event containing a reference to the item to remove
|
||||
*/
|
||||
public void removePackageItem(ActionEvent event)
|
||||
{
|
||||
UIActionLink link = (UIActionLink)event.getComponent();
|
||||
Map<String, String> params = link.getParameterMap();
|
||||
String nodeRef = new NodeRef(Repository.getStoreRef(), params.get("id")).toString();
|
||||
|
||||
if (this.packageItemsToAdd.contains(nodeRef))
|
||||
{
|
||||
// remove the item from the added list if it was added in this dialog session
|
||||
this.packageItemsToAdd.remove(nodeRef);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Removed item from the added list: " + nodeRef);
|
||||
}
|
||||
|
||||
// reset the rich list so it re-renders
|
||||
this.packageItemsRichList.setValue(null);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Bean Getters and Setters
|
||||
|
||||
/**
|
||||
* Returns a String array of NodeRef's that are being added to the workflow package
|
||||
*
|
||||
* @return String array of NodeRef's
|
||||
*/
|
||||
public String[] getItemsToAdd()
|
||||
{
|
||||
return this.itemsToAdd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the NodeRef's to add as items to the workflow package
|
||||
*
|
||||
* @param itemsToAdd NodeRef's to add to the workflow package
|
||||
*/
|
||||
public void setItemsToAdd(String[] itemsToAdd)
|
||||
{
|
||||
this.itemsToAdd = itemsToAdd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an item is currently being added to the workflow package
|
||||
*
|
||||
* @return true if an item is being added
|
||||
*/
|
||||
public boolean isItemBeingAdded()
|
||||
{
|
||||
return this.isItemBeingAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rich list being used for the workflow package items
|
||||
*
|
||||
* @param richList The rich list instance
|
||||
*/
|
||||
public void setPackageItemsRichList(UIRichList richList)
|
||||
{
|
||||
this.packageItemsRichList = richList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rich list being used for the workflow package items
|
||||
*
|
||||
* @return The rich list instance
|
||||
*/
|
||||
public UIRichList getPackageItemsRichList()
|
||||
{
|
||||
return this.packageItemsRichList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the workflow selected by the user
|
||||
*
|
||||
@@ -317,6 +486,59 @@ public class StartWorkflowWizard extends BaseWizardBean
|
||||
return availableWorkflows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of resources associated with this task
|
||||
* i.e. the children of the workflow package
|
||||
*
|
||||
* @return The list of nodes
|
||||
*/
|
||||
public List<Node> getResources()
|
||||
{
|
||||
this.resources = new ArrayList<Node>(4);
|
||||
|
||||
UserTransaction tx = null;
|
||||
try
|
||||
{
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
tx = Repository.getUserTransaction(context, true);
|
||||
tx.begin();
|
||||
|
||||
for (String newItem : this.packageItemsToAdd)
|
||||
{
|
||||
NodeRef nodeRef = new NodeRef(newItem);
|
||||
if (this.nodeService.exists(nodeRef))
|
||||
{
|
||||
// create our Node representation
|
||||
MapNode node = new MapNode(nodeRef, this.nodeService, true);
|
||||
this.browseBean.setupCommonBindingProperties(node);
|
||||
|
||||
// add property resolvers to show path information
|
||||
node.addPropertyResolver("path", this.browseBean.resolverPath);
|
||||
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
|
||||
|
||||
this.resources.add(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
|
||||
}
|
||||
}
|
||||
|
||||
// commit the transaction
|
||||
tx.commit();
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
|
||||
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
|
||||
this.resources = Collections.<Node>emptyList();
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
|
||||
}
|
||||
|
||||
return this.resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the workflow service to use
|
||||
*
|
||||
|
@@ -0,0 +1,48 @@
|
||||
package org.alfresco.web.bean.workflow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
|
||||
|
||||
/**
|
||||
* Bean implementation for the "View Completed Task" dialog.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class ViewCompletedTaskDialog extends ManageTaskDialog
|
||||
{
|
||||
// ------------------------------------------------------------------------------
|
||||
// Dialog implementation
|
||||
|
||||
@Override
|
||||
protected String finishImpl(FacesContext context, String outcome)
|
||||
throws Exception
|
||||
{
|
||||
// nothing to do as the finish button is not shown and the dialog is read only
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCancelButtonLabel()
|
||||
{
|
||||
return Application.getMessage(FacesContext.getCurrentInstance(), "close");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DialogButtonConfig> getAdditionalButtons()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle()
|
||||
{
|
||||
String titleStart = Application.getMessage(FacesContext.getCurrentInstance(), "view_completed_task_title");
|
||||
|
||||
return titleStart + ": " + this.task.title;
|
||||
}
|
||||
}
|
@@ -39,8 +39,8 @@ public class WorkflowBean
|
||||
{
|
||||
protected NodeService nodeService;
|
||||
protected WorkflowService workflowService;
|
||||
protected List<Node> workItems;
|
||||
protected List<Node> completedWorkItems;
|
||||
protected List<Node> tasks;
|
||||
protected List<Node> completedTasks;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(WorkflowBean.class);
|
||||
|
||||
@@ -48,12 +48,12 @@ public class WorkflowBean
|
||||
// Bean Getters and Setters
|
||||
|
||||
/**
|
||||
* Returns a list of nodes representing the to do work items the
|
||||
* Returns a list of nodes representing the to do tasks the
|
||||
* current user has.
|
||||
*
|
||||
* @return List of to do work items
|
||||
* @return List of to do tasks
|
||||
*/
|
||||
public List<Node> getWorkItemsToDo()
|
||||
public List<Node> getTasksToDo()
|
||||
{
|
||||
// get the current username
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
@@ -71,14 +71,14 @@ public class WorkflowBean
|
||||
userName, WorkflowTaskState.IN_PROGRESS);
|
||||
|
||||
// create a list of transient nodes to represent
|
||||
this.workItems = new ArrayList<Node>(tasks.size());
|
||||
this.tasks = new ArrayList<Node>(tasks.size());
|
||||
for (WorkflowTask task : tasks)
|
||||
{
|
||||
Node node = createWorkItem(task);
|
||||
this.workItems.add(node);
|
||||
Node node = createTask(task);
|
||||
this.tasks.add(node);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Added to do work item: " + node);
|
||||
logger.debug("Added to do task: " + node);
|
||||
}
|
||||
|
||||
// commit the changes
|
||||
@@ -88,19 +88,19 @@ public class WorkflowBean
|
||||
{
|
||||
// rollback the transaction
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
|
||||
Utils.addErrorMessage("Failed to get to do work items: " + e.toString(), e);
|
||||
Utils.addErrorMessage("Failed to get to do tasks: " + e.toString(), e);
|
||||
}
|
||||
|
||||
return this.workItems;
|
||||
return this.tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of nodes representing the completed work items the
|
||||
* Returns a list of nodes representing the completed tasks the
|
||||
* current user has.
|
||||
*
|
||||
* @return List of completed work items
|
||||
* @return List of completed tasks
|
||||
*/
|
||||
public List<Node> getWorkItemsCompleted()
|
||||
public List<Node> getTasksCompleted()
|
||||
{
|
||||
// get the current username
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
@@ -118,14 +118,14 @@ public class WorkflowBean
|
||||
userName, WorkflowTaskState.COMPLETED);
|
||||
|
||||
// create a list of transient nodes to represent
|
||||
this.completedWorkItems = new ArrayList<Node>(tasks.size());
|
||||
this.completedTasks = new ArrayList<Node>(tasks.size());
|
||||
for (WorkflowTask task : tasks)
|
||||
{
|
||||
Node node = createWorkItem(task);
|
||||
this.completedWorkItems.add(node);
|
||||
Node node = createTask(task);
|
||||
this.completedTasks.add(node);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Added completed work item: " + node);
|
||||
logger.debug("Added completed task: " + node);
|
||||
}
|
||||
|
||||
// commit the changes
|
||||
@@ -135,10 +135,10 @@ public class WorkflowBean
|
||||
{
|
||||
// rollback the transaction
|
||||
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
|
||||
Utils.addErrorMessage("Failed to get completed work items: " + e.toString(), e);
|
||||
Utils.addErrorMessage("Failed to get completed tasks: " + e.toString(), e);
|
||||
}
|
||||
|
||||
return this.completedWorkItems;
|
||||
return this.completedTasks;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +164,7 @@ public class WorkflowBean
|
||||
// ------------------------------------------------------------------------------
|
||||
// Helper methods
|
||||
|
||||
public static Map<QName, Serializable> prepareWorkItemParams(Node node)
|
||||
public static Map<QName, Serializable> prepareTaskParams(Node node)
|
||||
{
|
||||
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
|
||||
|
||||
@@ -199,9 +199,6 @@ public class WorkflowBean
|
||||
params.put(assocQName, (Serializable)targets);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Prepared parameters: " + params);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -211,7 +208,7 @@ public class WorkflowBean
|
||||
*
|
||||
* @param task The task to create a representation of
|
||||
*/
|
||||
protected TransientMapNode createWorkItem(WorkflowTask task)
|
||||
protected TransientMapNode createTask(WorkflowTask task)
|
||||
{
|
||||
// get the type of the task
|
||||
WorkflowTaskDefinition taskDef = task.definition;
|
||||
|
Reference in New Issue
Block a user