From a5dc6d1c34edd1caa8152f005e40b475c611807f Mon Sep 17 00:00:00 2001 From: "Mark H. Wood" Date: Fri, 24 Mar 2017 17:16:05 -0400 Subject: [PATCH] [DS-2058] First cut at adding curation to Configurable Workflow --- .../curate/XmlWorkflowCuratorServiceImpl.java | 298 ++++++++++++++++++ .../service/XmlWorkflowCuratorService.java | 81 +++++ .../dspace/workflow/CurationTaskConfig.java | 232 ++++++++++++++ .../xmlworkflow/XmlWorkflowServiceImpl.java | 76 ++++- .../service/XmlWorkflowService.java | 36 ++- 5 files changed, 718 insertions(+), 5 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/curate/XmlWorkflowCuratorServiceImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/curate/service/XmlWorkflowCuratorService.java create mode 100644 dspace-api/src/main/java/org/dspace/workflow/CurationTaskConfig.java diff --git a/dspace-api/src/main/java/org/dspace/curate/XmlWorkflowCuratorServiceImpl.java b/dspace-api/src/main/java/org/dspace/curate/XmlWorkflowCuratorServiceImpl.java new file mode 100644 index 0000000000..e9a90c492a --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/curate/XmlWorkflowCuratorServiceImpl.java @@ -0,0 +1,298 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.curate; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.PostConstruct; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.service.CollectionService; +import org.dspace.core.Context; +import org.dspace.core.LogManager; +import org.dspace.curate.service.XmlWorkflowCuratorService; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; +import org.dspace.eperson.service.EPersonService; +import org.dspace.eperson.service.GroupService; +import org.dspace.services.ConfigurationService; +import org.dspace.workflow.CurationTaskConfig; +import org.dspace.xmlworkflow.RoleMembers; +import org.dspace.xmlworkflow.WorkflowConfigurationException; +import org.dspace.xmlworkflow.factory.XmlWorkflowFactory; +import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; +import org.dspace.xmlworkflow.service.XmlWorkflowService; +import org.dspace.xmlworkflow.state.Step; +import org.dspace.xmlworkflow.state.Workflow; +import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Manage interactions between curation and workflow. A curation task can be + * attached to a workflow step, to be executed during the step. + * + * @see CurationTaskConfig + * @author mwood + */ +@Service +public class XmlWorkflowCuratorServiceImpl + implements XmlWorkflowCuratorService +{ + private static final Logger LOG + = LoggerFactory.getLogger(XmlWorkflowCuratorServiceImpl.class); + + @Autowired(required = true) + protected XmlWorkflowFactory workflowFactory; + + @Autowired(required = true) + protected XmlWorkflowServiceFactory workflowServiceFactory; + + @Autowired(required = true) + protected ConfigurationService configurationService; + + @Autowired(required = true) + protected GroupService groupService; + + @Autowired(required = true) + protected EPersonService ePersonService; + + @Autowired(required = true) + protected CollectionService collectionService; + + @Autowired(required = true) + protected ClaimedTaskService claimedTaskService; + + protected XmlWorkflowService workflowService; + protected XmlWorkflowItemService workflowItemService; + + /** + * Initialize the bean (after dependency injection has already taken place). + * Called by "init-method" in Spring configuration. + * + * @throws Exception passed through. + */ + @PostConstruct + public void init() + throws Exception + { + workflowService = workflowServiceFactory.getXmlWorkflowService(); + workflowItemService = workflowServiceFactory.getXmlWorkflowItemService(); + } + + @Override + public boolean needsCuration(XmlWorkflowItem wfi) + { + throw new UnsupportedOperationException("Not supported yet."); // TODO + } + + @Override + public boolean doCuration(Context c, XmlWorkflowItem wfi) + throws AuthorizeException, IOException, SQLException + { + Curator curator = new Curator(); + return curate(curator, c, wfi); + } + + @Override + public boolean curate(Curator curator, Context c, String wfId) + throws AuthorizeException, IOException, SQLException + { + XmlWorkflowItem wfi = workflowItemService.find(c, Integer.parseInt(wfId)); + if (wfi != null) { + return curate(curator, c, wfi); + } else { + LOG.warn(LogManager.getHeader(c, "No workflow item found for id: {}", null), wfId); + } + return false; + } + + @Override + public boolean curate(Curator curator, Context c, XmlWorkflowItem wfi) + throws AuthorizeException, IOException, SQLException + { + CurationTaskConfig.FlowStep step = getFlowStep(c, wfi); + if (step != null) { + // assign collection to item in case task needs it + Item item = wfi.getItem(); + item.setOwningCollection(wfi.getCollection()); + for (CurationTaskConfig.Task task : step.tasks) { + curator.addTask(task.name); + curator.curate(item); + int status = curator.getStatus(task.name); + String result = curator.getResult(task.name); + String action = "none"; + switch (status) + { + case Curator.CURATE_FAIL: + // task failed - notify any contacts the task has assigned + if (task.powers.contains("reject")) + { + action = "reject"; + } + notifyContacts(c, wfi, task, "fail", action, result); + // if task so empowered, reject submission and terminate + if ("reject".equals(action)) + { + workflowService.sendWorkflowItemBackSubmission(c, wfi, + c.getCurrentUser(), null, + task.name + ": " + result); + return false; + } + break; + case Curator.CURATE_SUCCESS: + if (task.powers.contains("approve")) + { + action = "approve"; + } + notifyContacts(c, wfi, task, "success", action, result); + if ("approve".equals(action)) + { + // cease further task processing and advance submission + return true; + } + break; + case Curator.CURATE_ERROR: + notifyContacts(c, wfi, task, "error", action, result); + break; + default: + break; + } + curator.clear(); + } + } + return true; + } + + /** + * Find the flow step occupied by a work flow item. + * @param c session context. + * @param wfi the work flow item in question. + * @return the current flow step for the item, or null. + * @throws SQLException + * @throws IOException + */ + protected CurationTaskConfig.FlowStep getFlowStep(Context c, XmlWorkflowItem wfi) + throws SQLException, IOException + { + Collection coll = wfi.getCollection(); + String key = CurationTaskConfig.containsKey(coll.getHandle()) ? coll.getHandle() : "default"; + + ClaimedTask claimedTask + = claimedTaskService.findByWorkflowIdAndEPerson(c, wfi, c.getCurrentUser()); + CurationTaskConfig.TaskSet ts = CurationTaskConfig.findTaskSet(key); + if (ts != null) + { + for (CurationTaskConfig.FlowStep fstep : ts.steps) + { + if (fstep.step.equals(claimedTask.getStepID())) + { + return fstep; + } + } + } + return null; + } + + /** + * Send email to people who should be notified when curation tasks are run. + * + * @param c session context. + * @param wfi the work flow item being curated. + * @param task the curation task being applied. + * @param status status returned by the task. + * @param action action to be taken as a result of task status. + * @param message anything the code wants to say about the task run. + * @throws AuthorizeException passed through. + * @throws IOException passed through. + * @throws SQLException passed through. + */ + protected void notifyContacts(Context c, XmlWorkflowItem wfi, + CurationTaskConfig.Task task, + String status, String action, String message) + throws AuthorizeException, IOException, SQLException + { + List epa = resolveContacts(c, task.getContacts(status), wfi); + if (epa.size() > 0) { + workflowService.notifyOfCuration(c, wfi, epa, task.name, action, message); + } + } + + /** + * Develop a list of EPerson from a list of perhaps symbolic "contact" names. + * + * @param c session context. + * @param contacts the list of concrete and symbolic groups to resolve. + * @param wfi the work flow item associated with these groups via its current work flow step. + * @return the EPersons associated with the current state of {@code wfi} + * @throws AuthorizeException passed through. + * @throws IOException passed through. + * @throws SQLException passed through. + */ + protected List resolveContacts(Context c, List contacts, + XmlWorkflowItem wfi) + throws AuthorizeException, IOException, SQLException + { + List epList = new ArrayList<>(); + for (String contact : contacts) { + // decode contacts + if ("$flowgroup".equals(contact)) { + // special literal for current flowgoup + ClaimedTask claimedTask = claimedTaskService.findByWorkflowIdAndEPerson(c, wfi, c.getCurrentUser()); + String stepID = claimedTask.getStepID(); + Step step; + try { + Workflow workflow = workflowFactory.getWorkflow(wfi.getCollection()); + step = workflow.getStep(stepID); + } catch (WorkflowConfigurationException e) { + LOG.error("Failed to locate current workflow step for workflow item " + + String.valueOf(wfi.getID()), e); + return epList; + } + RoleMembers roleMembers = step.getRole().getMembers(c, wfi); + for (EPerson ep : roleMembers.getEPersons()) + epList.add(ep); + for (Group group : roleMembers.getGroups()) + epList.addAll(group.getMembers()); + } else if ("$colladmin".equals(contact)) { + Group adGroup = wfi.getCollection().getAdministrators(); + if (adGroup != null) { + epList.addAll(groupService.allMembers(c, adGroup)); + } + } else if ("$siteadmin".equals(contact)) { + EPerson siteEp = ePersonService.findByEmail(c, + configurationService.getProperty("mail.admin")); + if (siteEp != null) { + epList.add(siteEp); + } + } else if (contact.indexOf("@") > 0) { + // little shaky heuristic here - assume an eperson email name + EPerson ep = ePersonService.findByEmail(c, contact); + if (ep != null) { + epList.add(ep); + } + } else { + // assume it is an arbitrary group name + Group group = groupService.findByName(c, contact); + if (group != null) { + epList.addAll(groupService.allMembers(c, group)); + } + } + } + return epList; + } +} diff --git a/dspace-api/src/main/java/org/dspace/curate/service/XmlWorkflowCuratorService.java b/dspace-api/src/main/java/org/dspace/curate/service/XmlWorkflowCuratorService.java new file mode 100644 index 0000000000..8aeaef2204 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/curate/service/XmlWorkflowCuratorService.java @@ -0,0 +1,81 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.curate.service; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; +import org.dspace.curate.Curator; +import org.dspace.workflowbasic.BasicWorkflowItem; + +import java.io.IOException; +import java.sql.SQLException; +import org.dspace.workflow.WorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; + +/** + * Manage interactions between curation and workflow. + * Specifically, it is invoked in XmlWorkflowService to allow the + * performance of curation tasks during workflow. + * + * Copied from {@link WorkflowCurator} with minor refactoring. + * + * @author mwood + */ +public interface XmlWorkflowCuratorService +{ + /** + * Does this workflow item need curation now? + * + * @param wfi the item in question. + * @return true if the item is in a state needing curation. + */ + public boolean needsCuration(XmlWorkflowItem wfi); + + /** + * Determines and executes curation on a Workflow item. + * + * @param c the context + * @param wfi the workflow item + * @return true if curation was completed or not required, + * false if tasks were queued for later completion, + * or item was rejected + * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + */ + public boolean doCuration(Context c, XmlWorkflowItem wfi) + throws AuthorizeException, IOException, SQLException; + + /** + * Determines and executes curation of a Workflow item by ID. + * + * @param curator the curation context + * @param c the user context + * @param wfId the workflow item's ID + * @return true if TODO + * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + */ + public boolean curate(Curator curator, Context c, String wfId) + throws AuthorizeException, IOException, SQLException; + + /** + * Determines and executes curation of a Workflow item. + * + * @param curator the curation context + * @param c the user context + * @param wfi the workflow item + * @return true if TODO + * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + */ + public boolean curate(Curator curator, Context c, XmlWorkflowItem wfi) + throws AuthorizeException, IOException, SQLException; +} diff --git a/dspace-api/src/main/java/org/dspace/workflow/CurationTaskConfig.java b/dspace-api/src/main/java/org/dspace/workflow/CurationTaskConfig.java new file mode 100644 index 0000000000..e24bbc66e6 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/workflow/CurationTaskConfig.java @@ -0,0 +1,232 @@ + +package org.dspace.workflow; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; + +import static javax.xml.stream.XMLStreamConstants.CHARACTERS; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; + +/** + * Represent the mapping between collection workflows and curation tasks. + * This mapping is defined in {@code [DSpace]/config/workflow-curation.xml}. + * + *

Copied from {@link WorkflowCuratorServiceImpl}. + * + * @author mwood + */ +public class CurationTaskConfig +{ + private static final Map tsMap = new HashMap<>(); + + /** + * Look up a TaskSet by name. + * + * @param setName name of the sought TaskSet: collection handle or "default". + * @return the named TaskSet, or the default TaskSet if not found, or + * {@code null} if there is no default either. + * @throws IOException passed through. + */ + static public TaskSet findTaskSet(String setName) + throws IOException + { + if (tsMap.isEmpty()) + { + ConfigurationService configurationService + = DSpaceServicesFactory.getInstance().getConfigurationService(); + File cfgFile = new File(configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + + "workflow-curation.xml"); + loadTaskConfig(cfgFile); + } + + if (tsMap.containsKey(setName)) + return tsMap.get(setName); + else + return tsMap.get("default"); + } + + /** + * Is this task set name defined? + * + * @param name name of the task set sought. + * @return true if a set by that name is known. + */ + public static boolean containsKey(String name) + { + return tsMap.containsKey(name); + } + + @SuppressWarnings("null") + static protected void loadTaskConfig(File cfgFile) throws IOException + { + final Map collMap = new HashMap<>(); + final Map setMap = new HashMap<>(); + TaskSet taskSet = null; + FlowStep flowStep = null; + Task task = null; + String type = null; + try { + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLStreamReader reader = factory.createXMLStreamReader( + new FileInputStream(cfgFile), "UTF-8"); + while (reader.hasNext()) + { + switch (reader.next()) + { + case START_ELEMENT: + { + String eName = reader.getLocalName(); + if (null != eName) switch (eName) + { + case "mapping": + collMap.put(reader.getAttributeValue(0), + reader.getAttributeValue(1)); + break; + case "taskset": + taskSet = new TaskSet(reader.getAttributeValue(0)); + break; + case "flowstep": + int count = reader.getAttributeCount(); + String queue = (count == 2) ? + reader.getAttributeValue(1) : null; + flowStep = new FlowStep(reader.getAttributeValue(0), queue); + break; + case "task": + task = new Task(reader.getAttributeValue(0)); + break; + case "workflow": + type = "power"; + break; + case "notify": + type = reader.getAttributeValue(0); + break; + default: + break; + } + break; + } + case CHARACTERS: + if (task != null) { + if ("power".equals(type)) { + task.addPower(reader.getText()); + } else { + task.addContact(type, reader.getText()); + } + } + break; + case END_ELEMENT: + { + String eName = reader.getLocalName(); + if (null != eName) switch (eName) + { + case "task": + flowStep.addTask(task); + task = null; + break; + case "flowstep": + taskSet.addStep(flowStep); + break; + case "taskset": + setMap.put(taskSet.setName, taskSet); + break; + default: + break; + } break; + } + default: + break; + } + } + reader.close(); + + // stitch maps together + for (Map.Entry collEntry : collMap.entrySet()) + { + if (! "none".equals(collEntry.getValue()) && setMap.containsKey(collEntry.getValue())) + { + tsMap.put(collEntry.getKey(), setMap.get(collEntry.getValue())); + } + } + } catch (XMLStreamException xsE) { + throw new IOException(xsE.getMessage(), xsE); + } + } + + static public class TaskSet + { + public String setName = null; + public List steps = null; + + public TaskSet(String setName) + { + this.setName = setName; + steps = new ArrayList<>(); + } + + public void addStep(FlowStep step) + { + steps.add(step); + } + } + + static public class FlowStep + { + public String step = null; + public String queue = null; + public List tasks = null; + + public FlowStep(String stepStr, String queueStr) + { + this.step = stepStr; + this.queue = queueStr; + tasks = new ArrayList<>(); + } + + public void addTask(Task task) + { + tasks.add(task); + } + } + + static public class Task + { + public String name = null; + public List powers = new ArrayList<>(); + public Map> contacts = new HashMap<>(); + + public Task(String name) { this.name = name; } + + public void addPower(String power) { + powers.add(power); + } + + public void addContact(String status, String contact) + { + List sContacts = contacts.get(status); + if (sContacts == null) + { + sContacts = new ArrayList<>(); + contacts.put(status, sContacts); + } + sContacts.add(contact); + } + + public List getContacts(String status) + { + List ret = contacts.get(status); + return (ret != null) ? ret : new ArrayList(); + } + } +} diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java index e2ac626a6c..acde871b4d 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java @@ -22,6 +22,7 @@ import javax.mail.MessagingException; import javax.servlet.http.HttpServletRequest; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; @@ -45,6 +46,7 @@ import org.dspace.core.Context; import org.dspace.core.Email; import org.dspace.core.I18nUtil; import org.dspace.core.LogManager; +import org.dspace.curate.service.XmlWorkflowCuratorService; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.service.GroupService; @@ -124,6 +126,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { protected BitstreamService bitstreamService; @Autowired(required = true) protected ConfigurationService configurationService; + @Autowired(required = true) + protected XmlWorkflowCuratorService xmlWorkflowCuratorService; protected XmlWorkflowServiceImpl() { @@ -318,9 +322,12 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { * Executes an action and returns the next. */ @Override - public WorkflowActionConfig doState(Context c, EPerson user, HttpServletRequest request, int workflowItemId, - Workflow workflow, WorkflowActionConfig currentActionConfig) - throws SQLException, AuthorizeException, IOException, WorkflowException { + public WorkflowActionConfig doState(Context c, EPerson user, + HttpServletRequest request, int workflowItemId, Workflow workflow, + WorkflowActionConfig currentActionConfig) + throws SQLException, AuthorizeException, IOException, + MessagingException, WorkflowException + { try { XmlWorkflowItem wi = xmlWorkflowItemService.find(c, workflowItemId); Step currentStep = currentActionConfig.getStep(); @@ -333,6 +340,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } c.addEvent(new Event(Event.MODIFY, Constants.ITEM, wi.getItem().getID(), null, itemService.getIdentifiers(c, wi.getItem()))); + xmlWorkflowCuratorService.doCuration(c, wi); return processOutcome(c, user, workflow, currentStep, currentActionConfig, outcome, wi, false); } else { throw new AuthorizeException("You are not allowed to to perform this task."); @@ -631,6 +639,68 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } } + // send notices of curation activity + @Override + public void notifyOfCuration(Context c, XmlWorkflowItem wi, + List ePeople, String taskName, String action, String message) + throws SQLException, IOException + { + try + { + // Get the item title + String title = getItemTitle(wi); + + // Get the submitter's name + String submitter = getSubmitterName(wi); + + // Get the collection + Collection coll = wi.getCollection(); + + for (EPerson epa : ePeople) + { + Locale supportedLocale = I18nUtil.getEPersonLocale(epa); + Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "flowtask_notify")); + email.addArgument(title); + email.addArgument(coll.getName()); + email.addArgument(submitter); + email.addArgument(taskName); + email.addArgument(message); + email.addArgument(action); + email.addRecipient(epa.getEmail()); + email.send(); + } + } + catch (MessagingException e) + { + log.warn(LogManager.getHeader(c, "notifyOfCuration", + "cannot email users of workflow_item_id " + wi.getID() + + ": " + e.getMessage())); + } + } + + protected String getItemTitle(XmlWorkflowItem wi) throws SQLException + { + Item myitem = wi.getItem(); + String title = myitem.getName(); + + // only return the first element, or "Untitled" + if (StringUtils.isNotBlank(title)) + { + return title; + } + else + { + return I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled "); + } + } + + protected String getSubmitterName(XmlWorkflowItem wi) throws SQLException + { + EPerson e = wi.getSubmitter(); + + return getEPersonName(e); + } + /*********************************** * WORKFLOW TASK MANAGEMENT **********************************/ diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java index f1f72b1b28..015f2a9ac2 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java @@ -32,7 +32,7 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; * When an item is submitted and is somewhere in a workflow, it has a row in the * WorkflowItem table pointing to it. * - * Once the item has completed the workflow it will be archived + * Once the item has completed the workflow it will be archived. * * @author Bram De Schouwer (bram.deschouwer at dot com) * @author Kevin Van de Velde (kevin at atmire dot com) @@ -47,7 +47,23 @@ public interface XmlWorkflowService extends WorkflowService { public WorkflowActionConfig doState(Context c, EPerson user, HttpServletRequest request, int workflowItemId, Workflow workflow, WorkflowActionConfig currentActionConfig) throws SQLException, AuthorizeException, IOException, MessagingException, WorkflowException; - + /** + * Execute the actions associated with a state, and return the next state. + * + * @param c session context. + * @param user current user. + * @param workflow item is in this workflow. + * @param currentStep workflow step being executed. + * @param currentActionConfig describes the current step's action. + * @param currentOutcome the result of executing the current step (accept/reject/etc). + * @param wfi the Item being processed through workflow. + * @param enteredNewStep is the Item advancing to a new workflow step? + * @return the next step's action. + * @throws SQLException passed through. + * @throws AuthorizeException passed through. + * @throws IOException passed through. + * @throws WorkflowException if the current step's outcome is unrecognized. + */ public WorkflowActionConfig processOutcome(Context c, EPerson user, Workflow workflow, Step currentStep, WorkflowActionConfig currentActionConfig, ActionResult currentOutcome, XmlWorkflowItem wfi, boolean enteredNewStep) @@ -75,5 +91,21 @@ public interface XmlWorkflowService extends WorkflowService { public void removeUserItemPolicies(Context context, Item item, EPerson e) throws SQLException, AuthorizeException; + /** + * Send email to interested parties when curation tasks run. + * + * @param c session context. + * @param wi the item being curated. + * @param ePeople the interested parties. + * @param taskName the task that has been run. + * @param action the action indicated by the task (reject, approve, etc.) + * @param message anything the code wants to say about the task. + * @throws SQLException passed through. + * @throws IOException passed through. + */ + public void notifyOfCuration(Context c, XmlWorkflowItem wi, + List ePeople, String taskName, String action, String message) + throws SQLException, IOException; + public String getEPersonName(EPerson ePerson); }