Java tutorial
/** * Copyright 2009 Welocalize, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. * * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * */ package com.globalsight.everest.workflow; // java import java.io.File; import java.io.FileInputStream; import java.rmi.RemoteException; import java.sql.Connection; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.Vector; import org.apache.log4j.Logger; import org.dom4j.Document; import org.dom4j.Element; import org.jbpm.JbpmContext; import org.jbpm.graph.def.Node; import org.jbpm.graph.def.ProcessDefinition; import org.jbpm.graph.exe.ProcessInstance; import org.jbpm.graph.exe.Token; import org.jbpm.taskmgmt.exe.PooledActor; import org.jbpm.taskmgmt.exe.TaskInstance; import com.globalsight.diplomat.util.database.ConnectionPool; import com.globalsight.everest.company.CompanyThreadLocal; import com.globalsight.everest.foundation.EmailInformation; import com.globalsight.everest.foundation.Timestamp; import com.globalsight.everest.jobhandler.Job; import com.globalsight.everest.jobhandler.jobcreation.JobCreationMonitor; import com.globalsight.everest.page.SourcePage; import com.globalsight.everest.permission.Permission; import com.globalsight.everest.permission.PermissionManager; import com.globalsight.everest.permission.PermissionSet; import com.globalsight.everest.projecthandler.Project; import com.globalsight.everest.servlet.util.ServerProxy; import com.globalsight.everest.taskmanager.Task; import com.globalsight.everest.taskmanager.TaskImpl; import com.globalsight.everest.taskmanager.TaskInfo; import com.globalsight.everest.taskmanager.TaskInterimPersistenceAccessor; import com.globalsight.everest.usermgr.UserInfo; import com.globalsight.everest.util.system.SystemConfigParamNames; import com.globalsight.everest.util.system.SystemConfiguration; import com.globalsight.everest.util.system.SystemShutdownException; import com.globalsight.everest.util.system.SystemStartupException; import com.globalsight.everest.webapp.WebAppConstants; import com.globalsight.everest.webapp.pagehandler.administration.users.UserUtil; import com.globalsight.everest.workflowmanager.ArrorInfo; import com.globalsight.everest.workflowmanager.DefaultPathTasks; import com.globalsight.everest.workflowmanager.Workflow; import com.globalsight.everest.workflowmanager.WorkflowImpl; import com.globalsight.ling.common.URLEncoder; import com.globalsight.log.GlobalSightCategory; import com.globalsight.persistence.hibernate.HibernateUtil; import com.globalsight.scheduling.SchedulerConstants; import com.globalsight.util.AmbFileStoragePathUtils; import com.globalsight.util.Entry; import com.globalsight.util.StringUtil; import com.globalsight.util.XmlParser; import com.globalsight.util.mail.MailerHelper; import com.globalsight.util.mail.MailerWLRemote; /** * <code>WorkflowServerLocal</code> responsibles for communication with the * Jbpm's workflow engine. It provides support for workflow template and * workflow instance activities. * */ public class WorkflowServerLocal implements WorkflowServer { // PRIVATE STATIC VARIABLES private static final Logger s_logger = Logger.getLogger(WorkflowServerLocal.class.getName()); private MailerWLRemote m_mailHandler = null; private String m_capLoginUrl = null; private String m_adminEmailAddress = null; private Timestamp m_timestamp = new Timestamp(); private static Map completeWorkFlow = new HashMap(); // system wide parameter that determines whether the notification action is // active. // The values are 0 or 1 (inactive and active respectively). private int m_isNotificationActive = -1; // the value of the warning threshold (system wide parameter). private Float m_threshold = null; // determines whether the system-wide notification is enabled private boolean m_systemNotificationEnabled = EventNotificationHelper.systemNotificationEnabled(); // For "amb-118 login task detail directly" private HashMap<String, String> taskDeatilUrlParam = new HashMap<String, String>(); private static final String EXIT_NODE = "Exit"; // // PUBLIC CONSTRUCTORS // /** * Construct a WorkflowServerLocal object. * * @exception WorkflowException * - Workflow related exception. */ public WorkflowServerLocal() { } // //////////////////////////////////////////////////////////////////// // Begin: WorkflowServer Implementation Methods // //////////////////////////////////////////////////////////////////// /** * * @see com.globalsight.everest.workflow.WorkflowServer#acceptTask(com.globalsight.everest.workflowmanager.Workflow, * java.lang.String, long, * com.globalsight.everest.taskmanager.TaskInfo, * com.globalsight.everest.workflow.TaskEmailInfo) */ public void acceptTask(Workflow p_wfClone, String p_assignee, long p_nodeInstanceId, TaskInfo p_taskInfo, TaskEmailInfo p_emailInfo, boolean isSkipped) throws RemoteException, WorkflowException { JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_wfClone.getId()); Node node = WorkflowJbpmUtil.getNodeById(processInstance.getProcessDefinition(), p_nodeInstanceId); TaskInstance taskInstance = WorkflowJbpmUtil.getTaskInstanceByNode(processInstance, node, true); startTaskInstance(taskInstance, p_assignee); // Set up job start date Job job = p_wfClone.getJob(); if (job.getStartDate() == null) { job.setStartDate(new Date()); HibernateUtil.update(job); } String companyId = String.valueOf(p_wfClone.getCompanyId()); p_emailInfo.setCompanyId(companyId); //get Job Comments String comments = MailerHelper.getJobCommentsByJob(job); Object[] args = { WorkflowJbpmUtil.getActivityNameWithArrowName(node, "_" + companyId, processInstance, WorkflowConstants.TASK_TYPE_ACC), UserUtil.getUserNameById(p_assignee), capLoginUrl(), p_emailInfo.getPriorityAsString(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), comments }; if (!isSkipped) sendTaskActionEmailToUser(p_assignee, p_emailInfo, null, WorkflowMailerConstants.ACCEPT_TASK, args); // Add the assignee name to the emailInfo for overdue issue p_emailInfo.setAssigneesName(p_assignee); // Fist stop the "accept by" timer and then create a "complete by" // warning notification for this activity based on the accepted // time. if (isNotificationActive()) { int actionType = SchedulerConstants.ACCEPT_ACTIVITY; if (isSkipped) actionType = SchedulerConstants.SKIP_ACTIVITY; EventNotificationHelper.performSchedulingProcess(new Integer(actionType), p_nodeInstanceId, (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.ACCEPT_TYPE), node, p_taskInfo, EventNotificationHelper.getCurrentTime(), (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.COMPLETE_TYPE), getWarningThreshold(), p_emailInfo); } } catch (WorkflowException wfe) { // this exception happens if jbpm could not create the work // item // so we know that the workflow has been discarded s_logger.error( "acceptTask (workflow discarded) " + wfe.toString() + GlobalSightCategory.getLineContinuation() + " p_assignee=" + p_assignee + " p_nodeInstanceId=" + p_nodeInstanceId, wfe); throw new WorkflowException(WorkflowException.MSG_FAILED_TO_ACCEPT_CANCELED, null, wfe); } catch (Exception e) { s_logger.error("acceptTask " + e.toString() + GlobalSightCategory.getLineContinuation() + " p_assignee=" + p_assignee + " p_nodeInstanceId=" + p_nodeInstanceId, e); throw new WorkflowException(WorkflowException.MSG_FAILED_TO_ACCEPT, null, e); } finally { ctx.close(); } } /** * @see WorkflowServer.advanceTask(String, String, long, String, * DefaultPathTasks, TaskEmailInfo); */ @SuppressWarnings("unchecked") public WorkflowInstanceInfo advanceTask(Workflow p_wfClone, String p_assignee, long p_nodeInstanceId, String p_arrowLabel, DefaultPathTasks p_taskInfos, TaskEmailInfo p_emailInfo, String skipping) throws RemoteException, WorkflowException { int state = -1; List<WfTaskInfo> nextTaskInfos = null; JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_wfClone.getId()); String skipActivity = WorkflowJbpmUtil.getSkipActivity(processInstance); Node node = WorkflowJbpmUtil.getNodeById(processInstance.getProcessDefinition(), p_nodeInstanceId); /* only get the not ended task */ TaskInstance taskInstance = WorkflowJbpmUtil.getTaskInstanceByNode(processInstance, node, true); WorkflowInstance workflowInstance = WorkflowProcessAdapter.getProcessInstance(processInstance); // TODO getPreActivityName NextNodes nextNodes = nextNodeInstances(node.getName(), workflowInstance.getWorkflowInstanceTasks(), p_arrowLabel, getPreActivityName(skipActivity, workflowInstance.getWorkflowInstanceTasks())); // get a list of next nodes used for email notification and event // scheduling. At this point, the UDA for a possible condition node // will also be updated. int sz = nextNodes.size(); boolean isCompleted = sz == 0 || nextNodes.hasExitNode(); // if the completed task was not the last one, set the assigness of // next node(s) if (!isCompleted) { setAssigneesOfNextNodes(processInstance, nextNodes, p_taskInfos, p_emailInfo); } endTaskInstance(nextNodes, taskInstance, isCompleted, processInstance, p_arrowLabel, skipActivity, workflowInstance.getDefaultPathNode(), p_wfClone.getId(), p_assignee); // For task complete, the finish email info need the node's // activity. p_emailInfo.setPreNode(node); if (isCompleted) { // only notify task completion advanceTaskNotification(p_assignee, p_nodeInstanceId, null, p_emailInfo, null, processInstance, skipping, WorkflowConstants.TASK_TYPE_COM); // TomyD -- since jBPM would not return the correct state of a // workflow // (due to some time delays for event related purposes), we'll // assume that // the workflow is completed once the next node is "Exit" node. state = WorkflowConstants.STATE_COMPLETED; // well,the p_arrowLabel is param come from next node, // if the p_arrowLabel is null // that means it have none,yes ,all the workflow have finished. p_emailInfo.setAssigneesName(p_assignee); completeWorkFlow.put(workflowInstance.getId() + p_emailInfo.getJobName(), p_emailInfo); } else { state = WorkflowConstants.STATE_RUNNING; nextTaskInfos = new ArrayList<WfTaskInfo>(); for (int i = 0; i < sz; i++) { // It's possible that after a condition node, the same node // gets // activated. Therefore, we need to consider it as the next // node. WorkflowTaskInstance nextNode = (WorkflowTaskInstance) nextNodes.getNode(i); nextNode = (nextNode.getType() == WorkflowConstants.ACTIVITY && (nextNode.getTaskId() == p_nodeInstanceId || !nextNodes.wasActive(nextNode))) ? nextNode : null; // the notification is both for completion of a task and the // starting // of the next possible task(s). Since we're looping thru a // list of // possible next tasks, we should only send the completion // email once. p_assignee = i == 0 ? p_assignee : null; ArrayList emailInfo = advanceTaskNotification(p_assignee, p_nodeInstanceId, nextNode == null ? null : p_taskInfos.getTaskInfoById(nextNode.getTaskId()), p_emailInfo, WorkflowJbpmUtil.getNodeByWfTask(processInstance, nextNode), processInstance, skipping, WorkflowConstants.TASK_TYPE_COM); if (nextNode != null) { // now add it to the list of next WfTaskInfo objects WfTaskInfo taskInfo = new WfTaskInfo(nextNode.getTaskId(), getSystemActionTypeForNode(nextNode, processInstance)); taskInfo.userEmail = emailInfo; nextTaskInfos.add(taskInfo); } } } } catch (Exception e) { s_logger.info("advanceTask " + e.toString() + GlobalSightCategory.getLineContinuation() + p_assignee + " p_emailInfo=" + (p_emailInfo != null ? p_emailInfo.toString() : "null") + " p_nodeInstanceId=" + Long.toString(p_nodeInstanceId)); String pm = p_emailInfo.getProjectManagerId(); try { pm = getEmailInfo(pm).getEmailAddress(); } catch (Exception e1) { // ignore... } String[] args = { String.valueOf(p_nodeInstanceId), pm }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_ADVANCE, args, e); } finally { ctx.close(); } return new WorkflowInstanceInfo(p_wfClone.getId(), state, nextTaskInfos); } public void advanceWorkFlowNotification(String key, String state) { TaskEmailInfo p_emailInfo = (TaskEmailInfo) completeWorkFlow.remove(key); if (p_emailInfo == null) { return; } Object[] args = { p_emailInfo.getJobName(), p_emailInfo.getAssigneesName(), capLoginUrl(), p_emailInfo.getPriorityAsString(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), state }; sendTaskActionEmailToUser(p_emailInfo.getAssigneesName(), p_emailInfo, null, WorkflowMailerConstants.COMPLETED_WFL, args); } /** * Creates a new workflow instance based on the given template id. * * @param p_wfTemplateId * - The id of the template that will be used for the creation of * a process. * * @return The newly created workflow instance. * * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ public WorkflowInstance createWorkflowInstance(long p_wfTemplateId) throws RemoteException, WorkflowException { WorkflowInstance wfi = null; JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessDefinition pd = ctx.getGraphSession().getProcessDefinition(p_wfTemplateId); /* * To support the modification of the workflow instance, we need to * copy a new version of processdefinition. The modification of the * instance will only affect the copy of the processdefiniton and * will not affect the original one. This copy will also generator a * new node id, this id will be used as the task id */ /* Gets the original xml of the given processdefinition */ FileInputStream in = new FileInputStream( AmbFileStoragePathUtils.getWorkflowTemplateXmlDir().getAbsolutePath() + File.separator + pd.getName() + WorkflowConstants.SUFFIX_XML); ProcessDefinition pdCopy = ProcessDefinition.parseXmlInputStream(in); ctx.deployProcessDefinition(pdCopy); ProcessInstance pi = pdCopy.createProcessInstance(); wfi = WorkflowProcessAdapter.getProcessInstance(pi); } catch (Exception e) { String args[] = { String.valueOf(p_wfTemplateId) }; s_logger.error("Failed to create wf instance. " + e.toString(), e); throw new WorkflowException(WorkflowException.MSG_FAILED_TO_CREATE_WF_INSTANCE, args, e); } finally { ctx.close(); } return wfi; } /** * Create a new workflow template. * * @param p_wfTemplate * - The template to be created. * @param p_worklfowOwners * - The owner (s) of the workflow instances. * * @return The created template with a valid id. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps iflow's exceptions. */ public WorkflowTemplate createWorkflowTemplate(WorkflowTemplate p_wfTemplate, WorkflowOwners p_workflowOwners) throws RemoteException, WorkflowException { try { return WorkflowTemplateAdapter.createInstance().createWorkflowTemplate(p_wfTemplate, p_workflowOwners); } catch (Exception e) { s_logger.error("Unable to create a workflow template due to the exception " + e); throw new WorkflowException(WorkflowException.MSG_FAILED_TO_CREATE_WF_TEMPLATE, null, e); } } /** * Import a workflow template. * * @param p_wfTemplate * - The template to be created. * @param doc * The workflow xml template document. * * @return The created template with a valid id. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps iflow's exceptions. */ public WorkflowTemplate importWorkflowTemplate(WorkflowTemplate p_wfTemplate, Document doc) throws RemoteException, WorkflowException { try { return WorkflowTemplateAdapter.createInstance().importWorkflowTemplate(p_wfTemplate, doc); } catch (Exception e) { s_logger.error("Unable to create a workflow template due to the exception " + e); throw new WorkflowException(WorkflowException.MSG_FAILED_TO_CREATE_WF_TEMPLATE, null, e); } } /** * Gets a list of tasks that are assigned by a specified project manager * based on the task state. * <p> * * @return map keyed by node.getId(), values are WorkflowTaskInstance * @param p_userId * - The current user id. * @param p_taskState * - The task state. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ public Map filterTasksForPM(String p_userId, int p_taskState) throws RemoteException { JbpmContext ctx = null; Map<Long, WorkflowTaskInstance> taskList = new HashMap<Long, WorkflowTaskInstance>(); try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); // first get the task instances that were assigned to PM. List<TaskInstance> taskInstances = WorkflowJbpmPersistenceHandler.getTaskInstances(p_userId, p_taskState, false, ctx); // then add the task instances that are visible by PM. taskInstances.addAll(WorkflowJbpmPersistenceHandler.getTaskInstances(p_userId, p_taskState, true, ctx)); convertAndMap(taskInstances, taskList, p_userId, p_taskState); } finally { ctx.close(); } return taskList; } /** * Get a list of currently active tasks of the specified workflow instance. * * @return A Map of active tasks (WorkflowTaskInstance objects) of the * specified workflow instance with the task id as the key. * * @param p_workflowInstanceId * - The id of the workflow instance. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ public Map<Long, WorkflowTaskInstance> getActiveTasksForWorkflow(long p_workflowInstanceId) throws RemoteException, WorkflowException { try { WorkflowInstance wi = WorkflowProcessAdapter.getProcessInstance(p_workflowInstanceId); Vector<WorkflowTaskInstance> wfTaskInstances = wi.getWorkflowInstanceTasks(); Map<Long, WorkflowTaskInstance> activeTasks = new HashMap<Long, WorkflowTaskInstance>( wfTaskInstances.size()); for (WorkflowTaskInstance wti : wfTaskInstances) { if (wti.getType() == WorkflowConstants.ACTIVITY && wti.getTaskState() == WorkflowConstants.STATE_RUNNING) { activeTasks.put(new Long(wti.getTaskId()), wti); updateInstanceOwner(p_workflowInstanceId, wti); } } return activeTasks; } catch (Exception e) { s_logger.error("getActiveTaskForWorkflow " + e.toString() + GlobalSightCategory.getLineContinuation() + " p_workflowInstanceId=" + p_workflowInstanceId, e); String args[] = { String.valueOf(p_workflowInstanceId) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_GET_ACTIVE_TASKS, args, e); } } private void updateInstanceOwner(long p_workflowInstanceId, WorkflowTaskInstance wti) throws Exception { JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_workflowInstanceId); TaskInstance taskInstance = WorkflowJbpmUtil.getTaskInstanceByNode(processInstance, wti.getNodeName()); wti.setAcceptUser(taskInstance.getActorId()); } catch (Exception e) { s_logger.error("updateInstanceOwner " + e.toString() + GlobalSightCategory.getLineContinuation() + " p_workflowInstanceId=" + p_workflowInstanceId, e); String args[] = { String.valueOf(p_workflowInstanceId) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_GET_TASKS_ACCEPT_USER, args, e); } finally { ctx.close(); } } /** * Gets a list of tasks that are assigned to a specified user based on the * task state. * <p> * * @return map keyed by node.getId(), values are WorkflowTaskInstance * @param p_userId * - The current user id. * @param p_taskState * - The task state. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ public Map getTasksForUser(String p_userId, int p_taskState) throws RemoteException { JbpmContext ctx = null; Map<Long, WorkflowTaskInstance> taskList = new HashMap<Long, WorkflowTaskInstance>(); try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); List<TaskInstance> taskInstances = WorkflowJbpmPersistenceHandler.getTaskInstances(p_userId, p_taskState, false, ctx); convertAndMap(taskInstances, taskList, p_userId, p_taskState); } finally { ctx.close(); } return taskList; } /** * Converts jbpm TaskInstance to WorkflowTaskInstance and put them in a map. * * @param p_taskInstances * a list of task instances. * @param p_taskList * the map * @param p_userId * the user id. * @param p_taskState * the task state being searched. */ private void convertAndMap(List<TaskInstance> p_taskInstances, Map<Long, WorkflowTaskInstance> p_taskList, String p_userId, int p_taskState) { List<Long> rejectTaskIds = WorkflowJbpmUtil.getRejectedTaskIds(p_taskInstances, p_userId); for (Iterator it = p_taskInstances.iterator(); it.hasNext();) { TaskInstance ti = (TaskInstance) it.next(); String activityName = WorkflowJbpmUtil.getActivityName(ti.getName()); long id = ti.getTask().getTaskNode().getId(); Long keyId = new Long(id); WorkflowTaskInstance wti = (WorkflowTaskInstance) p_taskList.get(keyId); if (wti == null) { wti = new WorkflowTaskInstance(activityName, WorkflowConstants.ACTIVITY); wti.setTaskId(id); wti.setActivity(new Activity(activityName)); String config = WorkflowJbpmUtil.getConfigure(ti.getTask().getTaskNode()); WorkflowNodeParameter param = WorkflowNodeParameter.createInstance(config); String assignees = WorkflowJbpmUtil.getAssignees(ti, p_userId); String acceptedTime = param.getAttribute(WorkflowConstants.FIELD_ACCEPTED_TIME); String completedTime = param.getAttribute(WorkflowConstants.FIELD_COMPLETED_TIME); String overdueToPM = param.getAttribute(WorkflowConstants.OVERDUETOPM); String overdueToUser = param.getAttribute(WorkflowConstants.OVERDUETOUSER); wti.setAcceptedTime(Long.parseLong(acceptedTime)); wti.setCompletedTime(Long.parseLong(completedTime)); if (overdueToPM != null && !"".equals(overdueToPM.trim()) && overdueToUser != null && !"".equals(overdueToUser.trim())) { wti.setOverdueToPM(Long.parseLong(overdueToPM)); wti.setOverdueToUser(Long.parseLong(overdueToUser)); } wti.setWorkItemAttributes(activityName, "", assignees, ti.getCreate().getTime(), WorkflowJbpmUtil.getStateFromTaskInstance(ti, p_userId, p_taskState, rejectTaskIds)); p_taskList.put(keyId, wti); } } } /** * Get a list of tasks (as WorkflowTask objects) for the specified workflow * instance. Note that all returned tasks are TYPE_ACTIVTY. * * @param p_workflowInstanceId * - The id of the workflow instance. * * @return A list of all tasks (as WorkflowTask objects) of the specified * workflow instance. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps workflow's exceptions. */ public Vector getTasksForWorkflow(long p_workflowInstanceId) throws RemoteException, WorkflowException { JbpmContext ctx = null; WorkflowInstance workflowInstance = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_workflowInstanceId); workflowInstance = WorkflowProcessAdapter.getProcessInstance(processInstance); } catch (Exception e) { e.printStackTrace(); } finally { ctx.close(); } return workflowInstance == null ? new Vector() : workflowInstance.getWorkflowInstanceTasks(); } /** * @see WorkflowServer.getVisitedTasksForWOrkflow(WFSession, long) */ @SuppressWarnings("unchecked") public List getVisitedTasksForWorkflow(long p_workflowInstanceId) throws RemoteException, WorkflowException { List<WorkflowTaskInstance> taskList = new ArrayList<WorkflowTaskInstance>(); JbpmContext ctx = null; WorkflowInstance workflowInstance = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_workflowInstanceId); workflowInstance = WorkflowProcessAdapter.getProcessInstance(processInstance); Vector tasks = workflowInstance.getWorkflowInstanceTasks(); for (Enumeration<WorkflowTaskInstance> e = tasks.elements(); e.hasMoreElements();) { WorkflowTaskInstance task = e.nextElement(); if (task.getType() == WorkflowConstants.ACTIVITY && task.getTaskState() != WorkflowConstants.STATE_INITIAL) { taskList.add(task); } } } catch (Exception e) { e.printStackTrace(); } finally { ctx.close(); } return taskList; } @SuppressWarnings("unchecked") public List<WorkflowTaskInstance> getUnVisitedTasksForWorkflow(long p_workflowInstanceId) throws RemoteException, WorkflowException { List<WorkflowTaskInstance> taskList = new ArrayList<WorkflowTaskInstance>(); JbpmContext ctx = null; WorkflowInstance workflowInstance = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_workflowInstanceId); workflowInstance = WorkflowProcessAdapter.getProcessInstance(processInstance); List<WorkflowTaskInstance> nodes = workflowInstance.getDefaultPathNode(); for (WorkflowTaskInstance task : nodes) { if (task.getType() == WorkflowConstants.ACTIVITY && task.getTaskState() == WorkflowConstants.STATE_INITIAL) { taskList.add(task); } } if (hasReachedExit(nodes.get(nodes.size() - 1))) { Vector tasks = workflowInstance.getWorkflowInstanceTasks(); for (Enumeration<WorkflowTaskInstance> e = tasks.elements(); e.hasMoreElements();) { WorkflowTaskInstance task = e.nextElement(); if (task.getType() == WorkflowConstants.STOP && !WorkflowConstants.START_NODE .equals(processInstance.getRootToken().getNode().getName())) { taskList.add(task); } } } } catch (Exception e) { e.printStackTrace(); } finally { ctx.close(); } return taskList; } private boolean hasReachedExit(WorkflowTaskInstance task) { Vector arrows = task.getOutgoingArrows(); WorkflowArrowInstance arrow = (WorkflowArrowInstance) arrows.get(0); WorkflowTaskInstance endTask = (WorkflowTaskInstance) arrow.getTargetNode(); if (endTask.getType() == WorkflowConstants.STOP) { return true; } if (endTask.getType() == WorkflowConstants.CONDITION) { Vector aarrows = endTask.getOutgoingArrows(); for (Enumeration ee = aarrows.elements(); ee.hasMoreElements();) { WorkflowArrow aarrow = (WorkflowArrow) ee.nextElement(); if (endTask.getConditionSpec().getBranchSpec(aarrow.getName()).isDefault()) { return aarrow.getTargetNode().getType() == WorkflowConstants.STOP; } } } return false; } /** * Get a particular workflow instance based on the given id. * * @param p_workflowInstanceId * - The id of the workflow instance to be retreived. * @return A WorkflowInstance object (if it exists). * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps workflow's exceptions. */ public WorkflowInstance getWorkflowInstanceById(long p_workflowInstanceId) throws RemoteException, WorkflowException { return WorkflowProcessAdapter.getProcessInstance(p_workflowInstanceId); } /** * @see WorkflowServer.getWorkflowTaskInfo(long) */ public WfTaskInfo getWorkflowTaskInfo(long p_workflowInstanceId, long p_taskId) throws RemoteException, WorkflowException { JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_workflowInstanceId); ProcessDefinition processDefinition = processInstance.getProcessDefinition(); Node node = WorkflowJbpmUtil.getNodeById(processDefinition, p_taskId); return new WfTaskInfo(p_taskId, getSystemActionTypeForNode(node, processInstance)); } catch (Exception e) { s_logger.error("Error occured when process the second target file", e); } finally { ctx.close(); } /* If error occured, return a null action type */ return new WfTaskInfo(p_taskId, null); } /** * Gets a particular task of a workflow instance. This method is used when * retrieving a workflow task for a project manager. * * @return A specified task (node) of a workflow instance. * @param p_userId * - the pm id. * @param p_taskId * - The id of the workflow instance task. * @param p_state * - The task state. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ public WorkflowTaskInstance getWorkflowTaskInstance(String p_userId, long p_taskId, int p_state) throws RemoteException, WorkflowException { JbpmContext ctx = WorkflowConfiguration.getInstance().getJbpmContext(); TaskInstance taskInstance = WorkflowJbpmPersistenceHandler.getTaskInstance(p_taskId, ctx); WorkflowTaskInstance wti = null; try { Node node = taskInstance.getTask().getTaskNode(); wti = WorkflowProcessAdapter.workflowTaskInstance(taskInstance, p_userId); String assignees = WorkflowJbpmUtil.getAssignees(taskInstance, p_userId); wti.setWorkItemAttributes(WorkflowJbpmUtil.getActivityName(node), "", assignees, taskInstance.getCreate().getTime(), WorkflowJbpmUtil.getStateFromTaskInstance(taskInstance, p_userId, p_state)); } catch (Exception e) { String args[] = { String.valueOf(p_taskId) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_GET_WF_INSTANCE, args, e); } finally { ctx.close(); } return wti; } /** * @see WorkflowServer.getWorkflowTaskInstance(long, long) */ @SuppressWarnings("unchecked") public WorkflowTaskInstance getWorkflowTaskInstance(long p_wfId, long p_taskId) throws RemoteException, WorkflowException { WorkflowTaskInstance wti = null; WorkflowInstance workflowInstance = null; JbpmContext ctx = WorkflowConfiguration.getInstance().getJbpmContext(); try { ProcessInstance processInstance = ctx.getProcessInstance(p_wfId); workflowInstance = WorkflowProcessAdapter.getProcessInstance(processInstance); Vector tasks = workflowInstance.getWorkflowInstanceTasks(); for (Enumeration<WorkflowTaskInstance> e = tasks.elements(); e.hasMoreElements();) { WorkflowTaskInstance task = e.nextElement(); if (task.getTaskId() == p_taskId) { return task; } } } catch (Exception e) { String args[] = { String.valueOf(p_taskId) }; s_logger.error("Error when get the WorkflowTaskInstance"); throw new WorkflowException(WorkflowException.MSG_FAILED_TO_GET_WF_INSTANCE, args, e); } finally { ctx.close(); } return wti; } /** * Gets a task of a workflow instance for a particular user. This method is * used when retrieving a workflow task for a translator/reviewer/etc. (for * a project manager use getWorkflowTaskInstance). * <p> * * @return A the specified task (node) of a workflow instance. * @param p_assignee * - The task's assignee. * @param p_taskId * - The task node id. * @param p_state * - The task state. * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps workflow's exceptions. */ public WorkflowTaskInstance getWorkflowTaskInstanceForAssignee(String p_assignee, long p_taskId, int p_state) throws RemoteException, WorkflowException { JbpmContext ctx = WorkflowConfiguration.getInstance().getJbpmContext(); TaskInstance taskInstance = WorkflowJbpmPersistenceHandler.getTaskInstance(p_taskId, ctx); Set<String> actorIds = PooledActor.extractActorIds(taskInstance.getPooledActors()); if (!actorIds.contains(p_assignee)) { throw new WorkflowException( new Exception(p_assignee + " do not have" + " the authority to operate the task.")); } WorkflowTaskInstance wfTaskInstance = null; try { Node node = taskInstance.getTask().getTaskNode(); wfTaskInstance = WorkflowProcessAdapter.workflowTaskInstance(taskInstance, p_assignee); wfTaskInstance.setWorkItemAttributes(WorkflowJbpmUtil.getActivityName(node), "", p_assignee, taskInstance.getCreate().getTime(), WorkflowJbpmUtil.getStateFromTaskInstance(taskInstance, p_assignee, p_state)); } catch (Exception e) { String args[] = { String.valueOf(p_taskId) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_GET_WF_INSTANCE, args, e); } finally { ctx.close(); } return wfTaskInstance; } /** * @see WorkflowServer.getWorkflowTemplateById(long) */ public WorkflowTemplate getWorkflowTemplateById(long p_templateId) throws RemoteException, WorkflowException { try { return WorkflowTemplateAdapter.createInstance().getWorkflowTemplate(p_templateId); } catch (Exception e) { String args[] = { String.valueOf(p_templateId) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_GET_WF_TEMPLATE, args, e); } } /** * Modify an existing workflow template. Since i-Flow does not allow the * modification of a template that has an active associated instance, we * create a new template and return the new id for updating the workflow * template info object. * * @param p_wfTemplate * - The template to be modified. * @param p_worklfowOwners * - The owner (s) of the workflow instances. * @return The modified workflow template template. * * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps workflow's exceptions. */ public WorkflowTemplate modifyWorkflowTemplate(WorkflowTemplate p_wfTemplate, WorkflowOwners p_workflowOwners) throws RemoteException, WorkflowException { try { // TomyD -- NEED TO CREATE A NEW ONE INSTEAD OF MODIFYING THE // EXISTING // TEMPLATE. A template that has an associate process in an // active state can not be modified. return createWorkflowTemplate(p_wfTemplate, p_workflowOwners); } catch (Exception e) { String args[] = { String.valueOf(p_wfTemplate.getId()) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_UPDATE_WF_TEMPLATE, args, e); } } /** * @see WorkflowServer.modifyWorkflowInstance(String, WorkflowInstance, * DefaultPathTasks, TaskEmailInfo) */ public Map modifyWorkflowInstance(String p_sessionId, WorkflowInstance p_wfInstance, DefaultPathTasks p_taskInfos, TaskEmailInfo p_emailInfo) throws RemoteException, WorkflowException { JbpmContext ctx = WorkflowConfiguration.getInstance().getJbpmContext(); Map newAndDeleted = null; List originalTasks = new ArrayList(0); List persistedTasks = new ArrayList(0); try { // TomyD -- Temp for Customer Upload feature. ProcessInstance processInstance = ctx.getProcessInstance(p_wfInstance.getId()); WorkflowProcessAdapter processAdapter = WorkflowProcessAdapter.createInstance(); // TomyD -- Temp for Customer Upload feature. if (p_sessionId == null) { setAdminAsOwner(processInstance); } // determine the state of workflow before modification. boolean isWfCompleted = processInstance.hasEnded(); // get the original workflow tasks (ONLY ActivityNodes before the // modification) originalTasks = processAdapter.workflowTaskInstances(processInstance); // perform the structural edit. WorkflowProcessAdapter.updateWorkflowProcessInstance(p_wfInstance, processInstance); // now get the list of updated activities (ONLY Activity Nodes) persistedTasks = processAdapter.workflowTaskInstances(processInstance); // notify user(s) for a newly added and activate task for a workflow // that was in completed state if (isWfCompleted) { /* should never be here */ // List activeNodes = piInfo.getActiveNodes(); // int size = activeNodes == null ? 0 : activeNodes.size(); // for (int i = 0; i < size; i++) // { // NodeInstance activeNode = (NodeInstance) activeNodes.get(i); // TaskInfo taskInfo = p_taskInfos.getTaskInfoById(activeNode // .getNodeInstanceId()); // // if (m_systemNotificationEnabled) // { // notifyTaskIsAdvanced(null, null, wfSession, // p_emailInfo, activeNode, taskInfo); // } // // // // add the warning/deadline timer if feature is // // activated. // // EventNotificationHelper.scheduleNotificationForDispatch( // // activeNode, taskInfo, p_emailInfo, // // isNotificationActive(), getWarningThreshold()); // } } // only perform node activation update for an active process else { performNodeActivation(persistedTasks, processInstance, processInstance.getProcessDefinition(), originalTasks, p_taskInfos, p_emailInfo); } } catch (WorkflowException wfe) // send back the appropriate workflow // exception { throw wfe; } catch (Exception e) { String args[] = { String.valueOf(p_wfInstance.getId()) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_UPDATE_WF_INSTANCE, args, e); } finally { ctx.close(); } updateWorkflowInstanceId(p_wfInstance, persistedTasks); try { newAndDeleted = newAndDeletedTasks(originalTasks, persistedTasks); } catch (Exception e) { String args[] = { String.valueOf(p_wfInstance.getId()) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_UPDATE_WF_INSTANCE, args, e); } return newAndDeleted; } /** * Sets the task id for the WorkflowTaskInstance when the node is new added. * * @param p_wfInstance * The WorkflowTaskInstance. * @throws Exception */ public void updateWorkflowInstanceId(WorkflowInstance p_wfInstance, List persistedTasks) { JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_wfInstance.getId()); ProcessDefinition processDefinition = processInstance.getProcessDefinition(); Vector tasks = p_wfInstance.getWorkflowInstanceTasks(); for (Enumeration e = tasks.elements(); e.hasMoreElements();) { WorkflowTaskInstance taskInstance = (WorkflowTaskInstance) e.nextElement(); setTaskInstanceId(taskInstance, processDefinition); } for (Iterator it = persistedTasks.iterator(); it.hasNext();) { WorkflowTaskInstance taskInstance = (WorkflowTaskInstance) it.next(); setTaskInstanceId(taskInstance, processDefinition); } } finally { ctx.close(); } } private void setTaskInstanceId(WorkflowTaskInstance p_wfTask, ProcessDefinition p_processDefinition) { if (p_wfTask.getType() != WorkflowConstants.START && p_wfTask.getType() != WorkflowConstants.STOP) { if (p_wfTask.getTaskId() <= 0) { /* set the task id */ Node node = WorkflowJbpmUtil.getNodeByNodeName(p_processDefinition, p_wfTask.getNodeName()); p_wfTask.setTaskId(node.getId()); } } } /** * @see WorkflowServer.rejectTask(String, String, long, TaskInfo, * TaskEmailInfo) */ public void rejectTask(String p_assignee, long p_nodeInstanceId, TaskInfo p_taskInfo, TaskEmailInfo p_emailInfo) throws RemoteException { JbpmContext ctx = WorkflowConfiguration.getInstance().getJbpmContext(); try { TaskInstance taskInstance = WorkflowJbpmPersistenceHandler.getTaskInstance(p_nodeInstanceId, ctx); String config = WorkflowJbpmUtil.getConfigure(taskInstance.getTask().getTaskNode()); WorkflowNodeParameter param = WorkflowNodeParameter.createInstance(config); // update the actorId or pooledActors in the task instance. WorkflowJbpmUtil.updateAssignees(taskInstance, p_assignee, param); String pm = param.getAttribute(WorkflowConstants.FIELD_PM); Set pooledActors = PooledActor.extractActorIds(taskInstance.getPooledActors()); if (!(p_assignee.equals(pm) && pooledActors.contains(p_assignee) && pooledActors.size() == 1)) { /* save the reject variable to the database */ WorkflowJbpmPersistenceHandler.saveTaskVariable(ctx, WorkflowConstants.VARIABLE_IS_REJECTED, p_assignee, taskInstance); } WorkflowJbpmUtil.setPrivateValue(taskInstance, "start", null); int initialState = -1; initialState = WorkflowJbpmUtil.getStateFromTaskInstance(taskInstance, p_assignee, WorkflowConstants.TASK_ALL_STATES); Object[] args = { WorkflowJbpmUtil.getActivityName(taskInstance.getTask().getTaskNode()), UserUtil.getUserNameById(p_assignee), p_emailInfo.getComments(), capLoginUrl(), p_emailInfo.getPriorityAsString(), p_emailInfo.getJobName(), WorkflowHelper .localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US") }; sendTaskActionEmailToUser(p_assignee, p_emailInfo, null, WorkflowMailerConstants.REJECT_TASK, args); // The base time for newly created "accpet by" timer should be // the creation date of the work item since we're dealing with // an existing work item. if (initialState == WorkflowConstants.TASK_ACCEPTED && isNotificationActive()) { EventNotificationHelper.performSchedulingProcess(new Integer(SchedulerConstants.UNACCEPT_ACTIVITY), p_nodeInstanceId, (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.COMPLETE_TYPE), taskInstance.getTask().getTaskNode(), p_taskInfo, new Long(taskInstance.getCreate().getTime()), (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.ACCEPT_TYPE), getWarningThreshold(), p_emailInfo); } } finally { ctx.close(); } } /** * @see WorkflowServer.startWorkflow(WFSession, long, DefaultPathTasks, * TaskEmailInfo) */ public List<WfTaskInfo> startWorkflow(long p_workflowInstanceId, DefaultPathTasks p_taskInfos, TaskEmailInfo p_emailInfo) throws RemoteException, WorkflowException { JbpmContext ctx = null; try { // must get a WF session that is the admin - since we // don't have the owner's (PM) userid and password for // this method. ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance ppi = ctx.getProcessInstance(p_workflowInstanceId); WorkflowInstance workflowInstance = WorkflowProcessAdapter.getProcessInstance(ppi); String skipActivity = WorkflowJbpmUtil.getSkipActivity(ppi); NextNodes nextNodes = nextNodeInstances(null, workflowInstance.getWorkflowInstanceTasks(), null, getPreActivityName(skipActivity, workflowInstance.getDefaultPathNode())); // Gets all the assigees' names of this activity for overdue issue. String[] assignees = setAssigneesOfNextNodes(ppi, nextNodes, p_taskInfos, p_emailInfo); String assigneesName = ""; if (assignees != null) { int i = assignees.length; for (int n = 0; n < i; n++) { if (n != 0) { assigneesName += ","; } assigneesName += assignees[n]; } } p_emailInfo.setAssigneesName(assigneesName); // start the worklow and advance to the appropriate task ppi.signal(); signalProcess(ppi, skipActivity, workflowInstance.getDefaultPathNode(), p_workflowInstanceId); int sz = nextNodes.size(); List<WfTaskInfo> nextTaskInfos = new ArrayList<WfTaskInfo>(); for (int i = 0; i < sz; i++) { WorkflowTaskInstance nextNode = (WorkflowTaskInstance) nextNodes.getNode(i); TaskInfo taskInfo = p_taskInfos.getTaskInfoById(nextNode.getTaskId()); if (nextNode.getType() == WorkflowConstants.ACTIVITY) { ArrayList emailInfos = notifyTaskIsAdvanced(null, p_emailInfo, WorkflowJbpmUtil.getNodeByWfTask(ppi, nextNode), taskInfo, ppi, null, WorkflowConstants.TASK_TYPE_NEW); // Only create a warning notification for the first activity // (accpet timer) EventNotificationHelper.scheduleNotificationForDispatch( WorkflowJbpmUtil.getNodeByWfTask(ppi, nextNode), taskInfo, p_emailInfo, isNotificationActive(), getWarningThreshold()); // now add it to the list of next WfTaskInfo objects WfTaskInfo wfTaskInfo = new WfTaskInfo(nextNode.getTaskId(), getSystemActionTypeForNode(nextNode, ppi)); wfTaskInfo.userEmail = emailInfos; nextTaskInfos.add(wfTaskInfo); } } return nextTaskInfos; } catch (Exception e) { s_logger.error("startWorkflow: " + e.toString() + GlobalSightCategory.getLineContinuation() + " p_workflowInstanceId=" + Long.toString(p_workflowInstanceId) + " p_emailInfo=" + (p_emailInfo != null ? p_emailInfo.toString() : "null"), e); throw new WorkflowException(WorkflowException.EX_START_ERROR, WorkflowException.MSG_FAILED_TO_START_WORKFLOW, e); } finally { ctx.close(); } } private String getPreActivityName(String skipActivity, List<WorkflowTaskInstance> tasks) { if (skipActivity == null) { return null; } WorkflowTaskInstance temTask = null; for (WorkflowTaskInstance task : tasks) { if (task.getActivityName().equals(skipActivity)) { break; } temTask = task; } return temTask == null ? WorkflowConstants.START_NODE : temTask.getActivityName(); } /** * Suspend the specified workflow instance. This process is done by * de-activating the currently active task. * <p> * * @param p_workflowInstanceId * - The id of the workflow instance. * @param p_emailInfo * Information to be used or included in any emails sent out. * * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ public void suspendWorkflow(long p_workflowInstanceId, TaskEmailInfo p_emailInfo) throws RemoteException { JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance pi = ctx.getProcessInstance(p_workflowInstanceId); Collection taskInstances = pi.getTaskMgmtInstance().getTaskInstances(); String companyIdStr = MailerHelper.getCompanyId(p_emailInfo); pi.suspend(); String localePair = WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"); ArrayList<String> assignees = null; // There is no taskInstance, when the task didn't dispatch. if (null == taskInstances || taskInstances.size() == 0) { Object[] arguments = { "", UserUtil.getUserNameById(p_emailInfo.getProjectManagerId()), capLoginUrl(), p_emailInfo.getJobName(), localePair }; sendSingleTaskActionEmailToUser(p_emailInfo.getProjectManagerId(), p_emailInfo, p_emailInfo.getAccepterName(), assignees, WorkflowMailerConstants.CANCEL_TASK, arguments); } else { for (Iterator it = taskInstances.iterator(); it.hasNext();) { TaskInstance ti = (TaskInstance) it.next(); Node node = ti.getTask().getTaskNode(); assignees = new ArrayList<String>(); if (ti.getActorId() == null) { Set pa = ti.getPooledActors(); Set actors = PooledActor.extractActorIds(pa); for (Iterator its = actors.iterator(); its.hasNext();) { assignees.add((String) its.next()); } } else { assignees.add(ti.getActorId()); } Object[] args = { WorkflowJbpmUtil.getActivityNameWithArrowName(node, "_" + companyIdStr, pi, ""), UserUtil.getUserNameById(p_emailInfo.getProjectManagerId()), capLoginUrl(), p_emailInfo.getJobName(), localePair }; // Modify for GBS-1004 /* * String[] a = new String[assignees.size()]; * sendTaskActionEmailToUsers * (p_emailInfo.getProjectManagerId(), assignees.toArray(a), * p_emailInfo.getProjectIdAsLong(), null, * WorkflowMailerConstants.CANCEL_TASK, args); */ sendSingleTaskActionEmailToUser(p_emailInfo.getProjectManagerId(), p_emailInfo, p_emailInfo.getAccepterName(), assignees, WorkflowMailerConstants.CANCEL_TASK, args); // Stop the "complete by" or "accept by" timer of this node. if (isNotificationActive()) { // since we don't have the WorkItem object, we don't // really // know what the state is. Therefore, we'll assume // "complete" // for now and we'll do another check for "accept" // during // the unscheduling process. EventNotificationHelper.performSchedulingProcess( new Integer(SchedulerConstants.CANCEL_WORKFLOW), node.getId(), null, null, null, null, null, getWarningThreshold(), p_emailInfo); } } } } finally { ctx.close(); } } /** * Notify (send email) to the participants of the active task of the * workflow specified. * * @param p_WFSession * - The WFSession object created through a singleton object. * @param p_workflowInstanceId * - The id of the workflow instance. * @param p_taskActionType * - the action that is being done that an email should be sent * out for. See WorkflowMailerConstants for the types. * @param p_emailInfo * - The information to be inluded in any emails sent out. The * arguments sent to be emailed must be in a certain order. See * the email resource property. * * @exception java.rmi.RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ public void notifyTaskParticipants(long p_workflowInstanceId, int p_taskActionType, TaskEmailInfo p_emailInfo) throws RemoteException, WorkflowException { if (!m_systemNotificationEnabled) { return; } JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_workflowInstanceId); WorkflowProcessAdapter processAdapter = WorkflowProcessAdapter.createInstance(); List activityNodes = processAdapter.workflowTaskInstances(processInstance); List<WorkflowTaskInstance> activeNodes = WorkflowProcessAdapter.getActiveNodeInstances(activityNodes); for (WorkflowTaskInstance task : activeNodes) { Object[] args = { task.getName(), capLoginUrl(), p_emailInfo.getPriorityAsString(), p_emailInfo.getPageName(), p_emailInfo.getTime(), p_emailInfo.getJobName(), p_emailInfo.getComments() }; sendTaskActionEmailToUsers(p_emailInfo.getProjectManagerId(), getNodeAssignees(WorkflowJbpmUtil.getNodeById(processInstance.getProcessDefinition(), task.getTaskId()), processInstance), p_emailInfo.getProjectIdAsLong(), null, p_taskActionType, args); } } catch (Exception e) { s_logger.error("notifyTaskParticipants: " + e.toString() + GlobalSightCategory.getLineContinuation() + " p_workflowInstanceId=" + Long.toString(p_workflowInstanceId) + " p_taskActionType=" + p_taskActionType + " p_emailInfo=" + (p_emailInfo != null ? p_emailInfo.toString() : "null"), e); } finally { ctx.close(); } } /** * Reassign all active/deactive activities of the given user to the project * manager. * * @param p_userId * - The user id of the assignee. * * @exception RemoteException * Network related exception. * @exception WorkflowException * - Wraps jbpm's exceptions. */ @SuppressWarnings("unchecked") public void reassignUserActivitiesToPm(String p_userId) throws RemoteException, WorkflowException { JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); List taskInstances = WorkflowJbpmPersistenceHandler.getNonRejectedTaskInstancesByAssignee(p_userId, ctx); for (Iterator it = taskInstances.iterator(); it.hasNext();) { TaskInstance ti = (TaskInstance) it.next(); String pm = ti.getDescription(); String actorId = ti.getActorId(); if (actorId != null && p_userId.equals(actorId)) { // clear the actors ti.setActorId(null); // clear the start date WorkflowJbpmUtil.setPrivateValue(ti, "start", null); } Set pooledActors = ti.getPooledActors(); // add pm to new pooled actors if (pooledActors != null && !pooledActors.isEmpty()) { Set<String> actorIds = PooledActor.extractActorIds(pooledActors); if (actorIds != null && actorIds.contains(p_userId)) { actorIds.remove(p_userId); actorIds.add(pm); ti.setPooledActors(WorkflowJbpmUtil.toStringArray(actorIds)); } } // for GBS-1302, reassign interim activity TaskInterimPersistenceAccessor.reassignInterimActivity(ti); } } finally { ctx.close(); } } /* * @see WorkflowServer.taskIdsInDefaultPath(long) */ public long[] taskIdsInDefaultPath(long p_workflowInstanceId) throws WorkflowException, RemoteException { WorkflowInstance workflowInstance = WorkflowProcessAdapter.getProcessInstance(p_workflowInstanceId); // get the NodeInstances of TYPE_ACTIVITY List nodesInPath = ProcessImplDefaultPathFinder.activityNodesInDefaultPath(p_workflowInstanceId, -1, null, WorkflowJbpmUtil.convertToArray(workflowInstance.getWorkflowInstanceTasks())); // now loop through the nodes and get the task ids long[] taskIds = new long[nodesInPath.size()]; for (int i = 0; i < nodesInPath.size(); i++) { taskIds[i] = ((WorkflowTaskInstance) nodesInPath.get(i)).getTaskId(); } return taskIds; } /** * @see WorkflowServer.timeDurationsInDefaultPath(long, long, String) * */ public List timeDurationsInDefaultPath(String p_destinationArrow, long p_workflowInstanceId, long p_startNodeId) throws WorkflowException, RemoteException { WorkflowInstance workflowInstance = WorkflowProcessAdapter.getProcessInstance(p_workflowInstanceId); // get the NodeInstances of TYPE_ACTIVITY List nodesInPath = workflowInstance.getDefaultPathNode(); return convertToWfTaskInfos(nodesInPath); } /* * (non-Javadoc) * * @see * com.globalsight.everest.workflow.WorkflowServer#timeDurationsInDefaultPath * (long, long, java.lang.String, * com.globalsight.everest.workflow.WorkflowInstance) */ public List timeDurationsInDefaultPath(long p_workflowInstanceId, long p_startNodeId, ArrorInfo p_destinationArrow, WorkflowInstance wfi) throws WorkflowException, RemoteException { List nodesInPath = wfi.getDefaultPathNode() == null || p_destinationArrow != null ? ProcessImplDefaultPathFinder.activityNodesInDefaultPath(p_workflowInstanceId, p_startNodeId, p_destinationArrow, WorkflowJbpmUtil.convertToArray(wfi.getWorkflowInstanceTasks())) : wfi.getDefaultPathNode(); return convertToWfTaskInfos(nodesInPath); } /** * @see WorkflowServer.assignWorkflowOwners(long, String, String[]) */ public void reassignWorkflowOwners(long p_workflowInstanceId, String p_projectManagerId, String[] p_workflowOwners) throws RemoteException, WorkflowException { /* * In Jbpm implementation, we don't use the project currently. This * function can be refined or removed by further investigation */ } public void signalProcess(ProcessInstance processInstance, String activity, List<WorkflowTaskInstance> taskInstances, long workflowId) { Connection connection = null; try { connection = ConnectionPool.getConnection(); if (activity != null) { Token token = processInstance.getRootToken(); for (WorkflowTaskInstance task : taskInstances) { if (task.getActivityName().equals(activity)) { break; } if (!task.getActivityName().equals(WorkflowJbpmUtil.getTaskName(token.getNode().getName()))) { continue; } if (task.getActivityName().equals(WorkflowJbpmUtil.getTaskName(token.getNode().getName()))) { String arrow = getArrowLabel(task); TaskInstance taskInstance = WorkflowJbpmUtil.getTaskInstanceByNode(processInstance, token.getNode()); if (StringUtil.isEmpty(arrow)) { taskInstance.end(); } else { taskInstance.setVariable(WorkflowConstants.VARIABLE_GOTO, arrow); taskInstance.end(); } try { // for GBS-1302, skip interim activity TaskInterimPersistenceAccessor .skipInterimActivity(taskInstance.getTask().getTaskNode().getId(), connection); } catch (Exception e) { } WorkflowJbpmPersistenceHandler.saveSkipVariable(taskInstance, workflowId); continue; } } removeSkip(processInstance); } } catch (Exception e) { s_logger.error("Error found in signalProcess.", e); } finally { ConnectionPool.silentReturnConnection(connection); } } private void removeSkip(ProcessInstance processInstance) { ProcessDefinition processDefinition = processInstance.getProcessDefinition(); Node exitNode = processDefinition.getNode(WorkflowConstants.END_NODE); WorkflowNodeParameter np = WorkflowNodeParameter.createInstance(exitNode); np.removeElement(WorkflowConstants.FIELD_SKIP); WorkflowJbpmUtil.setConfigure(exitNode, np.restore()); } private String getArrowLabel(WorkflowTaskInstance task) { if (task.getOutgoingArrows().size() == 1 && ((WorkflowArrow) task.getOutgoingArrows().get(0)) .getTargetNode().getType() != WorkflowConstants.CONDITION) { return null; } Vector arrows = task.getOutgoingArrows(); for (Enumeration e = arrows.elements(); e.hasMoreElements();) { WorkflowArrow arrow = (WorkflowArrow) e.nextElement(); WorkflowTaskInstance targetTask = (WorkflowTaskInstance) arrow.getTargetNode(); if (targetTask.getType() == WorkflowConstants.CONDITION) { Vector aarrows = targetTask.getOutgoingArrows(); for (Enumeration ee = aarrows.elements(); ee.hasMoreElements();) { WorkflowArrow aarrow = (WorkflowArrow) ee.nextElement(); if (targetTask.getConditionSpec().getBranchSpec(aarrow.getName()).isDefault()) { return aarrow.getName(); } } } } return null; } public void setSkipActivity(List<Entry> list, String userId, boolean internal) throws RemoteException, WorkflowException { JbpmContext ctx = null; Map<String, Boolean> map = new HashMap<String, Boolean>(); Map<String, String> activityMap = new HashMap<String, String>(); String taskName; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); for (Entry<String, String> entry : list) { String workflowId = entry.getKey(); String activity = entry.getValue(); ProcessInstance processInstance = ctx.getProcessInstance(Long.valueOf(workflowId)); boolean undispatched = processInstance.getRootToken().getNode().getName() .equals(WorkflowConstants.START_NODE); if (!undispatched) { taskName = WorkflowJbpmUtil.getTaskName(processInstance.getRootToken().getNode().getName()); activityMap.put(workflowId, taskName); } map.put(workflowId, Boolean.valueOf(undispatched)); } } finally { ctx.close(); } for (Entry<String, String> entry : list) { String workflowId = entry.getKey(); Workflow workflow = (Workflow) HibernateUtil.get(WorkflowImpl.class, Long.valueOf(workflowId)); try { int indexInDefaultPath = Integer.parseInt(entry.getHelp()); for (int i = 0; i <= indexInDefaultPath; i++) { if (!map.get(workflowId)) { Iterator it = ServerProxy.getTaskManager().getCurrentTasks(workflow.getId()).iterator(); Task task = null; if (it.hasNext()) { task = (Task) (it.next()); } else { return; } ServerProxy.getTaskManager().acceptTask(userId, task, true); if (i == indexInDefaultPath) { // i == indexInDefaultPath indicates this is the // last // activity to skip. ServerProxy.getTaskManager().completeTask(userId, task, null, "LAST_SKIPPING"); } else { ServerProxy.getTaskManager().completeTask(userId, task, null, "SKIPPING"); } try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); TaskInstance taskInstance = WorkflowJbpmPersistenceHandler.getTaskInstance(task.getId(), ctx); WorkflowJbpmPersistenceHandler.saveSkipVariable(taskInstance, workflow.getId()); } finally { ctx.close(); } } } } finally { if (!"Exit".equals(entry.getValue())) { // update workflow state back to DISPATCHED if it has not // ended JobCreationMonitor.updateWorkflowState(workflow, Workflow.DISPATCHED); } } } } public void setSkipActivity(List<Entry> list, String userId) throws RemoteException, WorkflowException { JbpmContext ctx = null; Map<String, Boolean> map = new HashMap<String, Boolean>(); Map<String, String> activityMap = new HashMap<String, String>(); String taskName; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); for (Entry<String, String> entry : list) { String workflowId = entry.getKey(); String activity = entry.getValue(); ProcessInstance processInstance = ctx.getProcessInstance(Long.valueOf(workflowId)); boolean undispatched = processInstance.getRootToken().getNode().getName() .equals(WorkflowConstants.START_NODE); if (!undispatched) { taskName = WorkflowJbpmUtil.getTaskName(processInstance.getRootToken().getNode().getName()); activityMap.put(workflowId, taskName); } map.put(workflowId, Boolean.valueOf(undispatched)); } } finally { ctx.close(); } for (Entry<String, String> entry : list) { String workflowId = entry.getKey(); String activity = entry.getValue(); // int indexInDefaultPath = Integer.parseInt(request // .getParameter("activity_" + workflowId)); // for (int i = 0; i <= indexInDefaultPath; i++) while (true) { try { if (!map.get(workflowId)) { Workflow workflow = (Workflow) HibernateUtil.get(WorkflowImpl.class, Long.valueOf(workflowId)); Iterator it = ServerProxy.getTaskManager().getCurrentTasks(workflow.getId()).iterator(); Task task = null; if (it.hasNext()) { task = (Task) (it.next()); if (activity.equals(task.getTaskName())) return; } else { return; } ServerProxy.getTaskManager().acceptTask(userId, task, true); if (task.getTaskName().equals("Exit")) { ServerProxy.getTaskManager().completeTask(userId, task, null, "LAST_SKIPPING"); } else { ServerProxy.getTaskManager().completeTask(userId, task, null, "SKIPPING"); } try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); TaskInstance taskInstance = WorkflowJbpmPersistenceHandler.getTaskInstance(task.getId(), ctx); WorkflowJbpmPersistenceHandler.saveSkipVariable(taskInstance, workflow.getId()); } finally { ctx.close(); } } } catch (Exception e) { s_logger.error(e.getMessage(), e); } } } } private Task getTask(WorkflowImpl workflow, String activity) { Set<TaskImpl> taskSet = workflow.getTaskSet(); for (TaskImpl task : taskSet) { if (activity.equals(task.getName())) { return task; } } return null; } private void setSkipActivityToNode(ProcessInstance processInstance, String activity) { ProcessDefinition processDefinition = processInstance.getProcessDefinition(); Node exitNode = processDefinition.getNode(WorkflowConstants.END_NODE); WorkflowNodeParameter nodeParameter = WorkflowNodeParameter.createInstance(exitNode); nodeParameter.setAttribute(WorkflowConstants.FIELD_SKIP, activity); WorkflowJbpmUtil.setConfigure(exitNode, nodeParameter.restore()); } // //////////////////////////////////////////////////////////////////// // End: WorkflowServer Implementation Methods // //////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////// // Begin: Package-scope Methods // //////////////////////////////////////////////////////////////////// /** * ======= // * //////////////////////////////////////////////////////////////////// // * Begin: Package-scope Methods // * //////////////////////////////////////////////////////////////////// /** * >>>>>>> .r2615 Performs the necessary steps when the system start-up is * invoked. */ void startup() throws SystemStartupException { s_logger.info("--- jBPM configuration loading... ---"); WorkflowConfiguration.getInstance(); s_logger.info("--- jBPM configuration loaded... ---"); } /** * Closes the jBPM configuration when the system shutdown is invoked. * * @throws SystemShutdownException */ void shutdown() { WorkflowConfiguration.getInstance().logout(); s_logger.info("--- jBPM configuration closed ---"); } // //////////////////////////////////////////////////////////////////// // End: Package-scope Methods // //////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////// // Begin: Private Support Methods // //////////////////////////////////////////////////////////////////// /* * Convert a list of NodeInstance objects to WfTaskInfo objects. */ @SuppressWarnings("unchecked") private List convertToWfTaskInfos(List p_nodesInPath) { List taskInfos = new ArrayList(p_nodesInPath.size()); for (Iterator it = p_nodesInPath.iterator(); it.hasNext();) { WorkflowTaskInstance taskInstance = (WorkflowTaskInstance) it.next(); long acceptanceDuration = taskInstance.getAcceptTime(); long completionDuration = taskInstance.getCompletedTime(); String[] roles = taskInstance.getRoles(); WfTaskInfo taskInfo = new WfTaskInfo(taskInstance.getTaskId(), taskInstance.getName(), acceptanceDuration, completionDuration, roles, taskInstance.getTaskState(), isFollowedByExit(taskInstance)); taskInfo.setOverdueToPM(taskInstance.getOverdueToPM()); taskInfo.setOverdueToUser(taskInstance.getOverdueToUser()); taskInfos.add(taskInfo); } return taskInfos; } private boolean isFollowedByExit(WorkflowTaskInstance taskInstance) { boolean followedByExit = false; Vector arrows = taskInstance.getOutgoingArrows(); Enumeration e = arrows.elements(); while (e.hasMoreElements()) { WorkflowArrow arrow = (WorkflowArrow) e.nextElement(); followedByExit = arrow.getTargetNode().getType() == WorkflowConstants.STOP; if (followedByExit) { break; } } return followedByExit; } /** * Activate a new task (and deactivate the old one). * */ private void activateTaskInstance(ProcessInstance p_processInstance, long p_taskId, String[] p_newRoles, String[] p_roles, String p_oldActivityName, DefaultPathTasks p_taskInfos, TaskEmailInfo p_emailInfo) throws Exception { JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); TaskInstance ti = WorkflowJbpmPersistenceHandler.getTaskInstance(p_taskId, ctx); Integer unscheduledEventType = 0; String[] previousAssignees = new String[p_roles.length]; for (int i = 0; i < p_roles.length; i++) { previousAssignees[i] = retrieveUserIdFromRole(p_roles[i]); } String[] newAssignees = new String[p_newRoles.length]; for (int i = 0; i < p_newRoles.length; i++) { newAssignees[i] = retrieveUserIdFromRole(p_newRoles[i]); } ti.setActorId(null); ti.setPooledActors(newAssignees); WorkflowJbpmUtil.setPrivateValue(ti, "start", null); // for GBS-1302, reassign interim activity TaskInterimPersistenceAccessor.reassignInterimActivity(ti); unscheduledEventType = (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.ACCEPT_TYPE); TaskInfo taskInfo = p_taskInfos.getTaskInfoById(p_taskId); // after a reassign we have to stop // existing timer and create a new one if (isNotificationActive()) { EventNotificationHelper.performSchedulingProcess(new Integer(SchedulerConstants.MODIFY_WORKFLOW), p_taskId, unscheduledEventType, ti.getTask().getTaskNode(), taskInfo, EventNotificationHelper.getCurrentTime(), (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.COMPLETE_TYPE), getWarningThreshold(), p_emailInfo); } String companyIdStr = p_emailInfo.getCompanyId(); String pmIdStr = p_emailInfo.getProjectManagerId(); Object[] deactiveArgs = { p_oldActivityName, UserUtil.getUserNameById(pmIdStr), capLoginUrl(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), p_emailInfo.getPriorityAsString() }; Object[] activeArgs = { WorkflowJbpmUtil.getActivityName(ti.getTask().getTaskNode()), capLoginUrl(), p_emailInfo.getPriorityAsString(), taskInfo.getAcceptByDate(), taskInfo.getCompleteByDate(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US") }; // notify deactivated and activated task assignees sendTaskActionEmailToUsers(pmIdStr, previousAssignees, p_emailInfo.getProjectIdAsLong(), null, WorkflowMailerConstants.CANCEL_TASK, deactiveArgs); sendTaskActionEmailToUsers(pmIdStr, newAssignees, p_emailInfo.getProjectIdAsLong(), null, WorkflowMailerConstants.REASSIGN_TASK, activeArgs); } catch (Exception e) { s_logger.error("commitTaskActivation: " + e.toString() + GlobalSightCategory.getLineContinuation() + " p_processInstance=" + WorkflowHelper.toDebugString(p_processInstance) + " node=" + WorkflowHelper.toDebugString(p_taskId) + " p_emailInfo=" + WorkflowHelper.toDebugString(p_emailInfo), e); String args[] = { String.valueOf(p_taskId) }; throw new WorkflowException(WorkflowException.MSG_FAILED_TO_COMMIT_TASK_ACTIVATION, args, e); } finally { ctx.close(); } } private String retrieveUserIdFromRole(String p_role) { String[] ss = p_role.split(" "); StringBuilder sb = new StringBuilder(); // 1000 Translation1_1000 en_US de_DE leo anyone int nameSize = ss.length - 4; for (int i = 0; i < nameSize; i++) { sb.append(ss[i + 4]); if (i + 1 < nameSize) { sb.append(" "); } } return sb.toString(); } /* Return a Map of WorkflowTaskInstances from the process instance. The */ /* key of the map is WorkflowConstant.IS_NEW or IS_DELETED. The value for */ /* * >>>>>>> .r2615 each key would be a list of newly added tasks and deleted * ones repectively */ private Map newAndDeletedTasks(List p_originalTasks, List p_modifiedTasks) throws Exception { int size = p_originalTasks.size(); Map<String, List> returnMap = new HashMap<String, List>(size); Map originalMap = WorkflowProcessAdapter.makeWorkflowTaskInstanceMap(p_originalTasks); Map modifiedMap = WorkflowProcessAdapter.makeWorkflowTaskInstanceMap(p_modifiedTasks); List<WorkflowTaskInstance> deletedWorkflowTaskInstances = new ArrayList<WorkflowTaskInstance>(size); for (int i = 0; i < size; i++) { WorkflowTaskInstance original = (WorkflowTaskInstance) p_originalTasks.get(i); WorkflowTaskInstance modified = (WorkflowTaskInstance) modifiedMap.get(new Long(original.getTaskId())); if (modified == null) { deletedWorkflowTaskInstances.add(original); } } // Loop through modifieds and find ones not in originals // Mark these as IS_NEW. size = p_modifiedTasks.size(); List<WorkflowTaskInstance> newWorkflowTaskInstances = new ArrayList<WorkflowTaskInstance>(size); for (int i = 0; i < size; i++) { WorkflowTaskInstance modified = (WorkflowTaskInstance) p_modifiedTasks.get(i); if (originalMap.get(new Long(modified.getTaskId())) == null) { newWorkflowTaskInstances.add(modified); } } returnMap.put(WorkflowConstants.IS_DELETED, deletedWorkflowTaskInstances); returnMap.put(WorkflowConstants.IS_NEW, newWorkflowTaskInstances); return returnMap; } private void performNodeActivation(List p_updatedTasks, ProcessInstance p_processInstance, ProcessDefinition p_processDefinition, List p_wfTaskInstances, DefaultPathTasks p_taskInfos, TaskEmailInfo p_emailInfo) throws Exception { List activeNodes = WorkflowProcessAdapter.getActiveNodeInstances(p_updatedTasks); Map map = addEmailInfo(p_processInstance, p_wfTaskInstances, activeNodes, p_emailInfo); int mapSize = map.size(); Integer listSize = (Integer) map.get(WorkflowConstants.LIST_SIZE); int size = listSize.intValue(); // at least one of the durations of active node has changed if (mapSize == size) { // TomyD -- TBD - need to know the create or // accepted date here. /* * Map durations = (Map)map.get(WorkflowConstants.UPDATE_EVENT); * EventNotificationHelper.determineEventUpdate(durations, * p_emailInfo, isNotificationActive(), getWarningThreshold()); */ } else if (map.size() > size) { for (int i = 0; i < size; i++) { Boolean isNew = (Boolean) map.get(WorkflowConstants.IS_NEW + i); if (isNew == null) { continue; } String[] newRoles = null; String[] roles = null; String oldActivityName = null; long taskId = ((Long) map.get(WorkflowConstants.TASK_ID + i)).longValue(); if (!isNew.booleanValue()) { newRoles = (String[]) map.get(WorkflowConstants.ROLE_FOR_ACTIVATE + i); roles = (String[]) map.get(WorkflowConstants.ROLE_FOR_DEACTIVATE + i); oldActivityName = (String) map.get(WorkflowConstants.NAME_FOR_DEACTIVATE + i); } activateTaskInstance(p_processInstance, taskId, newRoles, roles, oldActivityName, p_taskInfos, p_emailInfo); } } } /** * Adds the info required for sending email for reroute/reassign * * @param p_wfTaskInstances * The original {@WorkflowTaskInstance} * list. * @param p_activeNodes * The new {@code WorkflowTaskInstance} list. */ private Map addEmailInfo(ProcessInstance p_processInstance, List p_wfTaskInstances, List p_activeNodes, TaskEmailInfo p_emailInfo) throws Exception { // Get original active nodes as a hash map (id, task). Map originalActiveTasks = WorkflowProcessAdapter.getActiveWfTaskInstances(p_wfTaskInstances); Map<String, Object> map = new HashMap<String, Object>(4); // Loop thru the current nodes int size = p_activeNodes.size(); map.put(WorkflowConstants.LIST_SIZE, new Integer(size)); String companyIdStr = p_emailInfo.getCompanyId(); for (int i = 0; i < size; i++) { WorkflowTaskInstance workflowTaskInstance = (WorkflowTaskInstance) p_activeNodes.get(i); long activeNodeId = workflowTaskInstance.getTaskId(); WorkflowTaskInstance wfti = (WorkflowTaskInstance) originalActiveTasks.get(new Long(activeNodeId)); if (wfti != null) { String[] newRoles = workflowTaskInstance.getRoles(); String[] oriRoles = wfti.getRoles(); if (!workflowTaskInstance.getRoleType()) { // not user role (to get container roles) newRoles = getAllQualifiedUserRoles(workflowTaskInstance); } if (!wfti.getRoleType()) { // not user role (to get container roles) oriRoles = getAllQualifiedUserRoles(wfti); } if (haveRolesChanged(newRoles, oriRoles)) { map.put(WorkflowConstants.IS_NEW + i, Boolean.FALSE); map.put(WorkflowConstants.TASK_ID + i, new Long(activeNodeId)); map.put(WorkflowConstants.ROLE_FOR_ACTIVATE + i, newRoles); map.put(WorkflowConstants.ROLE_FOR_DEACTIVATE + i, oriRoles); Node node = WorkflowJbpmUtil.getNodeByWfTask(p_processInstance, wfti); map.put(WorkflowConstants.NAME_FOR_DEACTIVATE + i, wfti.getActivity() != null ? wfti.getActivity().getActivityName() : wfti.getName()); } // we need to add info for change in durations or role. This // info is used on event notification update. Map durationChangeMap = EventNotificationHelper.durationChangeMap(workflowTaskInstance, wfti.getAcceptTime(), wfti.getCompletedTime()); // it's possible that at least one duration (accept/complete) is // updated map.put(WorkflowConstants.UPDATE_EVENT + i, durationChangeMap); } else // we have a new active node { map.put(WorkflowConstants.IS_NEW + i, Boolean.TRUE); map.put(WorkflowConstants.TASK_ID + i, new Long(activeNodeId)); } } return map; } /** * Gets the user roles based on the all qualified role selection. */ private String[] getAllQualifiedUserRoles(WorkflowTaskInstance wfti) throws Exception { Activity activity = wfti.getActivity(); // 1000 Translation1_1000 en_US de_DE String roleAsString = wfti.getRolesAsString(); String sourceLocale = roleAsString.split(" ")[2]; String targetLocale = roleAsString.split(" ")[3]; List userInfos = ServerProxy.getUserManager().getUserInfos(activity.getActivityName(), sourceLocale, targetLocale); String[] userRoles = new String[userInfos.size()]; for (int i = 0; i < userInfos.size(); i++) { UserInfo ui = (UserInfo) userInfos.get(i); // make the user role like // "1000 Translation1_1000 en_US de_DE leoanyone" // to make sure retrieveUserIdFromRole() read the correct user name // in next step userRoles[i] = "roleId activityName sourceLocale targetLocale " + ui.getUserId(); } return userRoles; } /* Return the login URL for CAP */ private String capLoginUrl() { if (m_capLoginUrl == null) { m_capLoginUrl = getSystemConfigValue(SystemConfigParamNames.CAP_LOGIN_URL); } return m_capLoginUrl; } /** * Determines whether the two string arrays have different set of strings. * This is done to find out whether the current roles are different from the * previous ones. */ private boolean haveRolesChanged(String[] p_currentRoles, String[] p_previousRoles) { if (p_currentRoles.length != p_previousRoles.length) { return true; } for (int i = 0; i < p_currentRoles.length; i++) { String newUserId = retrieveUserIdFromRole(p_currentRoles[i]); String oriUserId = retrieveUserIdFromRole(p_previousRoles[i]); if (!newUserId.equals(oriUserId)) { return true; } } return false; } /** * Gets the next node in the workflow, from Task. If there is no next, then * return NULL. * * @param p_task * Currenct task * @param p_arrowLabel * Next label name(optional) * @param p_skipToAcitivity * activity name(optional) * @return * @throws Exception */ public WorkflowTaskInstance nextNodeInstances(Task p_task, String p_arrowLabel, String p_skipToAcitivity) throws Exception { WorkflowTaskInstance wti = null; JbpmContext ctx = null; try { ctx = WorkflowConfiguration.getInstance().getJbpmContext(); ProcessInstance processInstance = ctx.getProcessInstance(p_task.getWorkflow().getId()); Node node = WorkflowJbpmUtil.getNodeById(processInstance.getProcessDefinition(), p_task.getId()); NextNodes nextNodes = nextNodeInstances(node.getName(), WorkflowProcessAdapter.getProcessInstance(processInstance).getWorkflowInstanceTasks(), p_arrowLabel, p_skipToAcitivity); if (nextNodes.size() > 0) { wti = (WorkflowTaskInstance) nextNodes.getNode(0); } } finally { ctx.close(); } return wti; } /** * Return the node instances that will be activated after the current one. * Note that no Exit/Stop node will be returned * * @param p_workItem * - The current active work item. * @param p_nodeInstances * - An array of node instances. * @param p_arrowLabel * - The possible outgoing arrow label of a condition node (if * any). */ private NextNodes nextNodeInstances(String p_nodeName, Vector p_nodeInstances, String p_arrowLabel, String skipToAcitivity) { WorkflowTaskInstance taskInstance = null; if (skipToAcitivity != null) { taskInstance = WorkflowJbpmUtil.getTaskInstanceByActivity(p_nodeInstances, skipToAcitivity); } else if (StringUtil.isEmpty(p_nodeName)) { // if work item is null, we're starting a workflow (find start node) taskInstance = WorkflowJbpmUtil.getStartNode(p_nodeInstances); } else { taskInstance = WorkflowJbpmUtil.getCurrentTaskInstance(p_nodeInstances, p_nodeName); } return WorkflowProcessAdapter.nextNodeInstances(taskInstance, p_arrowLabel); } // private String getSystemActionTypeForNode(WorkflowTaskInstance p_node, ProcessInstance p_pi) { Node node = WorkflowJbpmUtil.getNodeByWfTask(p_pi, p_node); return getSystemActionTypeForNode(node, p_pi); } private String getSystemActionTypeForNode(Node p_node, ProcessInstance p_pi) { WorkflowNodeParameter nodeParameter = WorkflowNodeParameter .createInstance(WorkflowJbpmUtil.getConfigure(p_node)); return nodeParameter.getAttribute(WorkflowConstants.FIELD_ACTION_TYPE, WorkflowTaskInstance.NO_ACTION); } /* * Return a formatted string for the given timestamp, base on the given * locale */ private String format(Date p_date, Locale p_locale, TimeZone p_timeZone) { m_timestamp.setDate(p_date); m_timestamp.setLocale(p_locale); m_timestamp.setTimeZone(p_timeZone); return m_timestamp.toString(); } // get a system configuration value for a given name. private String getSystemConfigValue(String p_paramName) { String value = null; try { SystemConfiguration config = SystemConfiguration.getInstance(); value = config.getStringParameter(p_paramName); } catch (Exception e) { s_logger.error("WorkflowServerLocal :: getSystemConfigValue for parameter name: " + p_paramName, e); } return value; } /** * Perform an enactment edit and update the Assignee UDA value for the * process instance. * */ private String[] setAssigneesOfNextNodes(ProcessInstance p_pi, NextNodes p_nextNodes, DefaultPathTasks p_taskInfos, TaskEmailInfo p_emailInfo) { String[] assignees = null; try { Date newDate = new Date(); int sz = p_nextNodes.size(); for (int i = 0; i < sz; i++) { WorkflowTaskInstance node = (WorkflowTaskInstance) p_nextNodes.getNode(i); if (node.getType() != WorkflowConstants.ACTIVITY) { continue; } TaskInfo taskInfo = p_taskInfos.getTaskInfoById(node.getTaskId()); String roles = node.getRolesAsString(); String preference = node.getRolePreference(); // get the user ids of all the members of the roles String[] userIds = AssigneeFilter.getAssigneeList(roles.split(","), p_emailInfo.getProjectIdAsLong().longValue()); // not only get the assignees based on the role preference (if // any) assignees = WorkflowProcessAdapter.updateAssignees(userIds, p_pi, node, newDate, taskInfo, preference); boolean shouldNotify = assignees == null && WorkflowConstants.AVAILABLE_ROLE_PREFERENCE.equals(preference); if (shouldNotify) { notifyResourceUnavailability(p_emailInfo, node.getName(), taskInfo); } } } catch (Exception e) { try { } catch (Exception ex) { s_logger.error("Failed to cancel editing of process with id: " + p_pi.getId()); } s_logger.error("Failed to set node assignees of workflow: " + p_pi.getId(), e); } return assignees; } /** * @param p_node * @param p_pi * @return */ private String[] getNodeAssignees(Node p_node, ProcessInstance p_pi) { WorkflowNodeParameter nodeParameter = WorkflowNodeParameter .createInstance(WorkflowJbpmUtil.getConfigure(p_node)); return nodeParameter.getArrayAttribute(WorkflowConstants.FIELD_ROLE_ID); } /* * TomyD -- Temp for Customer Upload feature. Add iFlow's admin user as the * process owner so he can take more actions on a process instance or work * item. */ private void setAdminAsOwner(ProcessInstance p_processInstance) throws Exception { /* It seems the owner never be used in workflow related operation */ } /** * Sends the import initiator an email that this review-only task is ready * for acceptance. This sends an email to the person that initiated the * first file in the job. */ private void notifyImportInitiator(TaskInfo p_taskInfo, TaskEmailInfo p_emailInfo, int p_mailerMessageType, Object p_args[]) { XmlParser xmlParser = null; try { Task task = (Task) ServerProxy.getTaskManager().getTask(p_taskInfo.getId()); String companyIdStr = String.valueOf(task.getCompanyId()); List sourcePages = task.getSourcePages(); SourcePage sp1 = (SourcePage) sourcePages.get(0); String efxml = sp1.getRequest().getEventFlowXml(); // parse the efxml for the import initiator id xmlParser = XmlParser.hire(); Document document = xmlParser.parseXml(efxml); Element root = document.getRootElement(); org.dom4j.Node node = root.selectSingleNode("/eventFlowXml/source/@importInitiatorId"); if (node != null) { String importInitatorId = node.getText(); if (importInitatorId != null && importInitatorId.length() > 0) { EmailInformation emailInfo = getEmailInfo(importInitatorId); s_logger.debug("Emailing about review-only task to import initator " + importInitatorId); String subject = getEmailSubject(p_mailerMessageType); String message = getEmailMessage(p_mailerMessageType); sendMail(importInitatorId, emailInfo, subject, message, p_args, companyIdStr); } } } catch (Exception e) { s_logger.error("Failed to send e-mail to the import initiator about a review-only task.", e); } finally { if (xmlParser != null) { XmlParser.fire(xmlParser); } } } // //////////////////////////////////////////////////////////////////// // End: Private Support Methods // //////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////// // Begin: Email notification methods // //////////////////////////////////////////////////////////////////// /* Return the administrator's email address */ private String adminEmailAddress() { if (m_adminEmailAddress == null) { m_adminEmailAddress = getSystemConfigValue(SystemConfigParamNames.ADMIN_EMAIL); } return m_adminEmailAddress; } /* * Perform the advance task notification. Also remove a completion event * that was scheduled (if it's not already been fired) and create new event * for the next (if any) task. */ private ArrayList advanceTaskNotification(String p_assignee, long p_nodeInstanceId, TaskInfo p_taskInfo, TaskEmailInfo p_emailInfo, Node p_node, ProcessInstance p_processInstance, String skipping, String p_taskType) { ArrayList emailinfo = notifyTaskIsAdvanced(p_assignee, p_emailInfo, p_node, p_taskInfo, p_processInstance, skipping, p_taskType); // Fist stop the "complete by" timer of the node that was finished. // Then create a "accpet by" timer for the next activity. if (isNotificationActive()) { int actionType = SchedulerConstants.FINISH_ACTIVITY; if (skipping != null) { if (skipping.startsWith("LAST")) { actionType = SchedulerConstants.SKIP_FINISH_ACTIVITY; } else { actionType = SchedulerConstants.SKIP_ACTIVITY; } } EventNotificationHelper.performSchedulingProcess(new Integer(actionType), p_nodeInstanceId, (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.COMPLETE_TYPE), p_node, p_taskInfo, EventNotificationHelper.getCurrentTime(), (Integer) SchedulerConstants.s_eventTypes.get(SchedulerConstants.ACCEPT_TYPE), getWarningThreshold(), p_emailInfo); } return emailinfo; } /* Get email address of a user based on the user name */ private EmailInformation getEmailInfo(String p_userName) throws Exception { return ServerProxy.getUserManager().getEmailInformationForUser(p_userName); } /* Retrieve the appropriate email subject key for the particular task. */ private String getEmailSubject(int p_messageType) { String subject = null; switch (p_messageType) { case WorkflowMailerConstants.ACCEPT_TASK: subject = WorkflowMailerConstants.ACCEPT_TASK_SUBJECT; break; case WorkflowMailerConstants.ACTIVATE_TASK: subject = WorkflowMailerConstants.ACTIVATE_TASK_SUBJECT; break; case WorkflowMailerConstants.ACTIVATE_REVIEW_TASK: subject = WorkflowMailerConstants.ACTIVATE_REVIEW_TASK_SUBJECT; break; case WorkflowMailerConstants.CANCEL_TASK: subject = WorkflowMailerConstants.CANCEL_TASK_SUBJECT; break; case WorkflowMailerConstants.COMPLETED_TASK: subject = WorkflowMailerConstants.COMPLETED_TASK_SUBJECT; break; case WorkflowMailerConstants.COMPLETED_WFL: subject = WorkflowMailerConstants.COMPLETED_WFL_SUBJECT; break; case WorkflowMailerConstants.COMPLETED_JOB: subject = WorkflowMailerConstants.COMPLETED_JOB_SUBJECT; break; case WorkflowMailerConstants.NO_AVAILABLE_RESOURCE: subject = WorkflowMailerConstants.NO_AVAILABLE_RESOURCE_SUBJECT; break; case WorkflowMailerConstants.PAGE_EXPORTED_FOR_UPDATE: subject = WorkflowMailerConstants.PAGE_EXPORTED_FOR_UPDATE_SUBJECT; break; case WorkflowMailerConstants.PAGE_REIMPORTED: subject = WorkflowMailerConstants.PAGE_REIMPORTED_SUBJECT; break; case WorkflowMailerConstants.REASSIGN_TASK: subject = WorkflowMailerConstants.REASSIGN_TASK_SUBJECT; break; case WorkflowMailerConstants.REJECT_TASK: subject = WorkflowMailerConstants.REJECT_TASK_SUBJECT; break; } return subject; } /* * Retrieve the appropriate email message key according for the particular * task. */ private String getEmailMessage(int p_messageType) { String message = null; switch (p_messageType) { case WorkflowMailerConstants.ACCEPT_TASK: message = WorkflowMailerConstants.ACCEPT_TASK_MESSAGE; break; case WorkflowMailerConstants.ACTIVATE_TASK: message = WorkflowMailerConstants.ACTIVATE_TASK_MESSAGE; break; case WorkflowMailerConstants.ACTIVATE_REVIEW_TASK: message = WorkflowMailerConstants.ACTIVATE_REVIEW_TASK_MESSAGE; break; case WorkflowMailerConstants.CANCEL_TASK: message = WorkflowMailerConstants.CANCEL_TASK_MESSAGE; break; case WorkflowMailerConstants.COMPLETED_TASK: message = WorkflowMailerConstants.COMPLETED_TASK_MESSAGE; break; case WorkflowMailerConstants.COMPLETED_WFL: message = WorkflowMailerConstants.COMPLETED_WFL_MESSAGE; break; case WorkflowMailerConstants.COMPLETED_JOB: message = WorkflowMailerConstants.COMPLETED_JOB_MESSAGE; break; case WorkflowMailerConstants.NO_AVAILABLE_RESOURCE: message = WorkflowMailerConstants.NO_AVAILABLE_RESOURCE_MESSAGE; break; case WorkflowMailerConstants.PAGE_EXPORTED_FOR_UPDATE: message = WorkflowMailerConstants.PAGE_EXPORTED_FOR_UPDATE_MESSAGE; break; case WorkflowMailerConstants.PAGE_REIMPORTED: message = WorkflowMailerConstants.PAGE_REIMPORTED_MESSAGE; break; case WorkflowMailerConstants.REASSIGN_TASK: message = WorkflowMailerConstants.REASSIGN_TASK_MESSAGE; break; case WorkflowMailerConstants.REJECT_TASK: message = WorkflowMailerConstants.REJECT_TASK_MESSAGE; break; } return message; } /* Return the remote reference of the mailer interface. */ private MailerWLRemote getMailer() throws Exception { if (m_mailHandler == null) { m_mailHandler = ServerProxy.getMailer(); } return m_mailHandler; } /** * Notify PM and WFM that no resources were available to work on a * particular task (for a 'available' role preference). Therefore, by * default all it'll be assigned to all assignees. */ private void notifyResourceUnavailability(TaskEmailInfo p_emailInfo, String p_activityName, TaskInfo p_taskInfo) { if (!m_systemNotificationEnabled) { return; } Object[] args = { p_activityName, p_emailInfo.getPriorityAsString(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), capLoginUrl() }; sendTaskActionEmailToUser(null, p_emailInfo, null, WorkflowMailerConstants.NO_AVAILABLE_RESOURCE, args); } /** * notify a project manager about a completed task, and then let the users * of the next task know about it. This method is also used when a workflow * instance has started. * * @param p_taskType * task/activity type(new/accept/complete) */ private ArrayList notifyTaskIsAdvanced(String p_assignee, TaskEmailInfo p_emailInfo, Node p_node, TaskInfo p_taskInfo, ProcessInstance processInstance, String skipping, String p_taskType) { ArrayList emailInfos = new ArrayList(); if (!m_systemNotificationEnabled) { return null; } try { // The args don't include restricted attachment informations. String companyId = CompanyThreadLocal.getInstance().getValue(); String companyName = ServerProxy.getJobHandler().getCompanyById(Long.parseLong(companyId)).getName(); p_emailInfo.setCompanyId(companyId); if (p_assignee != null) { Object[] args = { WorkflowJbpmUtil.getActivityNameWithArrowName(p_emailInfo.getPreNode(), "_" + companyId, processInstance, p_taskType), UserUtil.getUserNameById(p_assignee), capLoginUrl(), p_emailInfo.getPriorityAsString(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), p_emailInfo.getComments() }; if (skipping == null) { sendTaskActionEmailToUser(p_assignee, p_emailInfo, null, WorkflowMailerConstants.COMPLETED_TASK, args); } } if (p_node == null) { return null; } // notify the appropriate users about the next task (if there is // any) // -1 is the one before the first node at sequence 0 if (p_node != null) { String jobName = p_emailInfo.getJobName(); if (jobName != null) { jobName = jobName.replaceAll(" ", "%20"); } String linkUrl = capLoginUrl() + "/exports?" + "activityName=downloadXliff&xliff=true" + "&companyName=" + companyName + "&file=" + jobName + "_" + p_emailInfo.getSourceLocale() + "_" + p_emailInfo.getTargetLocale() + ".zip"; String activityName = WorkflowJbpmUtil.getActivityNameWithArrowName(p_node, "_" + companyId, processInstance, WorkflowConstants.TASK_TYPE_NEW); Object[] args = { activityName, capLoginUrl(), p_emailInfo.getPriorityAsString(), p_taskInfo.getAcceptByDate(), p_taskInfo.getCompleteByDate(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), String.valueOf(p_emailInfo.getSegmentTmMatchesWordCount()), String.valueOf(p_emailInfo.getLeverageMatchThreshold()), String.valueOf(p_emailInfo.getTotalFuzzyMatchesWordCount()), String.valueOf(p_emailInfo.getNoMatchesWordCount()), String.valueOf(p_emailInfo.getRepetitionsWordCount()), p_emailInfo.getJobId(), p_emailInfo.getProjectName(), String.valueOf(p_emailInfo.getTotalWordCount()), p_emailInfo.getComments(), p_emailInfo.getAttachment(), linkUrl }; // The args include restricted attachment informations. Object[] restrictArgs = { activityName, capLoginUrl(), p_emailInfo.getPriorityAsString(), p_taskInfo.getAcceptByDate(), p_taskInfo.getCompleteByDate(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), String.valueOf(p_emailInfo.getSegmentTmMatchesWordCount()), String.valueOf(p_emailInfo.getLeverageMatchThreshold()), String.valueOf(p_emailInfo.getTotalFuzzyMatchesWordCount()), String.valueOf(p_emailInfo.getNoMatchesWordCount()), String.valueOf(p_emailInfo.getRepetitionsWordCount()), p_emailInfo.getJobId(), p_emailInfo.getProjectName(), String.valueOf(p_emailInfo.getTotalWordCount()), p_emailInfo.getRestrictComments(), p_emailInfo.getRestrictAttachment(), linkUrl }; // The args don't include job comment informations. Object[] noJobCommentArgs = { activityName, capLoginUrl(), p_emailInfo.getPriorityAsString(), p_taskInfo.getAcceptByDate(), p_taskInfo.getCompleteByDate(), p_emailInfo.getJobName(), WorkflowHelper.localePair(p_emailInfo.getSourceLocale(), p_emailInfo.getTargetLocale(), "en_US"), String.valueOf(p_emailInfo.getSegmentTmMatchesWordCount()), String.valueOf(p_emailInfo.getLeverageMatchThreshold()), String.valueOf(p_emailInfo.getTotalFuzzyMatchesWordCount()), String.valueOf(p_emailInfo.getNoMatchesWordCount()), String.valueOf(p_emailInfo.getRepetitionsWordCount()), p_emailInfo.getJobId(), p_emailInfo.getProjectName(), String.valueOf(p_emailInfo.getTotalWordCount()), "", new ArrayList(), linkUrl }; // For "amb-118 login task detail directly" initTaskDeatilUrlParam(p_taskInfo); String[] toUsers = getNodeAssignees(p_node, processInstance); emailInfos = (ArrayList) getMailer().getEmailAddresses(toUsers); int ActionType = WorkflowMailerConstants.ACTIVATE_TASK; if (toUsers != null) { String from = p_emailInfo.getProjectManagerId(); Long projectId = p_emailInfo.getProjectIdAsLong(); PermissionManager pm = Permission.getPermissionManager(); for (int i = 0; i < toUsers.length; i++) { String to = toUsers[i]; PermissionSet perSet = pm.getPermissionSetForUser(to); Object[] messageArgs; boolean viewJobCommentPerm = perSet.getPermissionFor(Permission.ACTIVITIES_COMMENTS_JOB); boolean restrictCommentPerm = perSet.getPermissionFor(Permission.COMMENT_ACCESS_RESTRICTED); // How to show job comments according to permission. if (restrictCommentPerm) { messageArgs = restrictArgs; } else if (viewJobCommentPerm) { messageArgs = args; } else { messageArgs = noJobCommentArgs; } if (skipping == null || (skipping != null && skipping.startsWith("LAST"))) sendTaskActionEmailToUsers(from, new String[] { to }, projectId, null, ActionType, messageArgs); } } boolean b_isDell = false; try { SystemConfiguration sc = SystemConfiguration.getInstance(); b_isDell = sc.getBooleanParameter(SystemConfigParamNames.IS_DELL); } catch (Exception ex) { s_logger.error("Failed to read IS_DELL param", ex); } if (b_isDell) { if (Task.TYPE_REVIEW == p_taskInfo.getType() && (skipping == null || (skipping != null && skipping.startsWith("LAST")))) { notifyImportInitiator(p_taskInfo, p_emailInfo, WorkflowMailerConstants.ACTIVATE_REVIEW_TASK, args); } } } } catch (Exception ne) { s_logger.error("notifyTaskIsAdvanced " + ne.toString(), ne); } return emailInfos; } /** * For "amb-118 login task detail directly" Make a link which logon task * detail directly for task accepter * * @param p_taskInfo * for get some info eg.task id etc. * @return link */ private String makeLoginToTaskUrl() { // make login url from email String paramStr = getUrlParamStrBaseParamMap(taskDeatilUrlParam); String url = addParameterToUrl(capLoginUrl(), paramStr); return url; } /** * Add a parameter to a url link * * @param p_rootUrl * p_rootUrl current url, please ensure the root url have exsit * any parameter,else must add "?" first * @param p_paramName * @param p_paramValue * @return */ @SuppressWarnings("deprecation") private void initTaskDeatilUrlParam(TaskInfo p_taskInfo) { String taskPageParam = "?linkName=detail&pageName=TK1A&taskAction=getTask&taskId=" + p_taskInfo.getId() + "&state=-10"; String forwardUrl = "/ControlServlet" + taskPageParam; forwardUrl = URLEncoder.encode(forwardUrl, "UTF-8"); taskDeatilUrlParam.put("linkName", "detail"); taskDeatilUrlParam.put("pageName", "TK1A"); taskDeatilUrlParam.put("taskAction", "getTask"); taskDeatilUrlParam.put("taskId", Long.toString(p_taskInfo.getId())); taskDeatilUrlParam.put(WebAppConstants.LOGIN_FROM, WebAppConstants.LOGIN_FROM_EMAIL); taskDeatilUrlParam.put("forwardUrl", forwardUrl); taskDeatilUrlParam.put("state", "-10");// all task status } private String getUrlParamStrBaseParamMap(HashMap p_paramMap) { StringBuilder paramStr = new StringBuilder(""); if (p_paramMap == null) { return ""; } Set keySet = p_paramMap.keySet(); Iterator iterator = keySet.iterator(); while (iterator.hasNext()) { String key = (String) iterator.next(); String value = (String) p_paramMap.get(key); if (key != null && !"".equals(key)) { paramStr.append("&").append(key).append("=").append(value); } } return paramStr.toString(); } /** * Add a parameter string to a url link * * @param p_rootUrl * current url , note: please ensure the root url have exsit any * parameter,else must add "?" first * @param p_paramStr * @return */ private String addParameterToUrl(String p_rootUrl, String p_paramStr) { // check this root url have no parameter if (p_rootUrl.indexOf("?") == -1) { p_rootUrl = p_rootUrl + "?temp="; } if (p_paramStr != null && !"".equals(p_paramStr)) { return p_rootUrl + p_paramStr; } else { return p_rootUrl; } } /* send the email... */ private void sendMail(String p_fromUserId, EmailInformation p_to, String p_subjectKey, String p_messageKey, Object[] p_messageArgs, String p_companyIdStr) { try { Locale locale = p_to.getEmailLocale(); String[] args = new String[p_messageArgs.length]; for (int i = 0; i < p_messageArgs.length; i++) { if (p_messageArgs[i] instanceof Date) { args[i] = format((Date) p_messageArgs[i], locale, p_to.getUserTimeZone()); } if (p_messageArgs[i] instanceof List) { List attachment = (List) p_messageArgs[i]; StringBuilder strBuff = new StringBuilder(); if (attachment.size() == 0) { continue; } for (Iterator iter = attachment.iterator(); iter.hasNext();) { File attFile = (File) iter.next(); strBuff.append(attFile.getAbsolutePath()); strBuff.append(","); } args[i] = strBuff.toString(); } else { args[i] = p_messageArgs[i].toString(); } } getMailer().sendMail(p_fromUserId, p_to, p_subjectKey, p_messageKey, args, p_companyIdStr); } catch (Exception e) { String address = "<null!>"; if (p_to != null) address = p_to.getEmailAddress(); s_logger.error("Failed to send email to " + address, e); } } // send an email to users, for notify the task/activity cancel action private void sendSingleTaskActionEmailToUser(String p_fromUserId, TaskEmailInfo p_emailInfo, String p_accepter, List<String> p_assignee, int p_taskActionType, Object[] p_messageArgs) { try { if (!m_systemNotificationEnabled) { return; } List<?> wfmUserNames = p_emailInfo.getWorkflowManagerIds(); int size = wfmUserNames.size(); boolean notifyPm = p_emailInfo.notifyProjectManager(); List<String> receiverList = new ArrayList<String>(); String receiver = null; // do not send email if not required if (size == 0 && !notifyPm) { return; } String companyIdStr = MailerHelper.getCompanyId(p_emailInfo); String subject = getEmailSubject(p_taskActionType); String message = getEmailMessage(p_taskActionType); // notify the accepter or all users if (null != p_accepter && p_accepter.length() > 0) { receiver = p_accepter; if (null != receiver && !receiverList.contains(receiver)) { receiverList.add(receiver); } } else { if (null != p_assignee && p_assignee.size() > 0) { receiverList = p_assignee; } } // notify PM if (notifyPm) { receiver = p_emailInfo.getProjectManagerId(); if (null != receiver && !receiverList.contains(receiver)) { receiverList.add(receiver); } } // notify all workflow managers (if any) for (int i = 0; i < size; i++) { receiver = (String) wfmUserNames.get(i); if (null != receiver && !receiverList.contains(receiver)) { receiverList.add(receiver); } } // send email for (int i = 0; i < receiverList.size(); i++) { sendMail(p_fromUserId, getEmailInfo(receiverList.get(i)), subject, message, p_messageArgs, companyIdStr); } } catch (Exception e) { s_logger.error("Failed to send email notification.", e); } } /* send an email to a user based on a workflow action (i.e. advancing */ /* or rejecting a task) */ public void sendJobActionEmailToUser(String p_fromUserId, TaskEmailInfo p_emailInfo, int p_taskActionType) { Object[] p_messageArgs = { p_emailInfo.getJobName(), capLoginUrl(), p_emailInfo.getAssigneesName(), p_emailInfo.getPriorityAsString() }; sendTaskActionEmailToUser(p_fromUserId, p_emailInfo, null, p_taskActionType, p_messageArgs); } public void sendTaskActionEmailToUser(String p_fromUserId, TaskEmailInfo p_emailInfo, String p_cc, int p_taskActionType, Object[] p_messageArgs) { try { if (!m_systemNotificationEnabled) { return; } boolean notifyPm = p_emailInfo.notifyProjectManager(); String projectManager = p_emailInfo.getProjectManagerId(); List<String> wfmUserNames = p_emailInfo.getWorkflowManagerIds(); // do not send email if not required if (!notifyPm && wfmUserNames.size() == 0) { return; } // Delete the ignored receipt, Details in GBS-2461&2462. Set<String> ignoredReceipt = p_emailInfo.getIgnoredReceipt(); if (ignoredReceipt != null && ignoredReceipt.size() > 0) { if (ignoredReceipt.contains(projectManager)) notifyPm = false; for (Iterator<String> it = wfmUserNames.iterator(); it.hasNext();) { if (ignoredReceipt.contains(it.next())) { it.remove(); } } } String companyIdStr = MailerHelper.getCompanyId(p_emailInfo); String subject = getEmailSubject(p_taskActionType); String message = getEmailMessage(p_taskActionType); if (notifyPm) { sendMail(p_fromUserId, getEmailInfo(projectManager), subject, message, p_messageArgs, companyIdStr); } // notify all workflow managers (if any) for (int i = 0; i < wfmUserNames.size(); i++) { if (notifyPm && projectManager.equalsIgnoreCase(wfmUserNames.get(i))) continue; sendMail(p_fromUserId, getEmailInfo(wfmUserNames.get(i)), subject, message, p_messageArgs, companyIdStr); } } catch (Exception e) { s_logger.error("Failed to send email notification.", e); } } /* * send an email to a group of users (filtered by role and project) based on * a workflow action */ private void sendTaskActionEmailToUsers(String p_initiator, String[] userIds, Long p_projectId, String p_cc, int p_taskActionType, Object[] p_messageArgs) { if (!m_systemNotificationEnabled) { return; } try { Project proj = ServerProxy.getProjectHandler().getProjectById(p_projectId); String companyIdStr = String.valueOf(proj.getCompanyId()); String from = getEmailInfo(p_initiator).getEmailAddress(); if (from != null) { List emailInfos = getMailer().getEmailAddresses(userIds); int size = emailInfos == null ? 0 : emailInfos.size(); for (int i = 0; i < size; i++) { EmailInformation to = (EmailInformation) emailInfos.get(i); if (to != null) { taskDeatilUrlParam.put(WebAppConstants.LOGIN_NAME_FIELD, UserUtil.getUserNameById(to.getUserId())); p_messageArgs[1] = makeLoginToTaskUrl(); sendMail(p_initiator, to, getEmailSubject(p_taskActionType), getEmailMessage(p_taskActionType), p_messageArgs, companyIdStr); } } } } catch (Exception e) { s_logger.error("Failed to send email notification to a group of users.", e); } } // //////////////////////////////////////////////////////////////////// // End: Email notification methods // //////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////// // Begin: Event notification support // //////////////////////////////////////////////////////////////////// // get the warning threshold for scheduling timers. private Float getWarningThreshold() { if (m_threshold == null) { try { String threshold = getSystemConfigValue(SystemConfigParamNames.TIMER_THRESHOLD); m_threshold = Float.valueOf(threshold); } catch (NumberFormatException e) { s_logger.error("WorkflowServerLocal :: invalid warning threshold. It's been reset to 75%", e); m_threshold = Float.valueOf(".75"); } } return m_threshold; } // determines whether the notification feature is active private boolean isNotificationActive() { if (m_isNotificationActive == -1) { try { SystemConfiguration config = SystemConfiguration.getInstance(); m_isNotificationActive = config.getIntParameter(SystemConfigParamNames.USE_WARNING_THRESHOLDS); } catch (Exception e) { s_logger.error("WorkflowServerLocal :: isNotificationActive. ", e); } } return m_isNotificationActive == 1; } /** * Ends the taskinstance. * * @param p_nextNodes * @param p_taskInstance * @param isCompleted * @param p_processInstance * @param p_arrowLabel * @throws SecurityException * @throws NoSuchFieldException * @throws IllegalArgumentException * @throws IllegalAccessException */ private void endTaskInstance(NextNodes p_nextNodes, TaskInstance p_taskInstance, boolean isCompleted, ProcessInstance p_processInstance, String p_arrowLabel, String activity, List<WorkflowTaskInstance> taskInstances, long workflowId, String assignee) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { if (!StringUtil.isEmpty(p_arrowLabel)) { /* set the variable for the condition branch */ p_taskInstance.setVariable(WorkflowConstants.VARIABLE_GOTO, p_arrowLabel); } else { // if the arrow is null, it indicates this is a skip operation p_taskInstance.setVariable(WorkflowConstants.VARIABLE_GOTO, WorkflowConstants.VARIABLE_GOTO_SKIP); } /* end the task */ p_taskInstance.end(); // for GBS-1302, end interim activity TaskInterimPersistenceAccessor.endInterimActivity(p_taskInstance); if (!StringUtil.isEmpty(activity)) { WorkflowJbpmPersistenceHandler.saveSkipVariable(p_taskInstance, workflowId); } signalProcess(p_processInstance, activity, taskInstances, workflowId); if (!isCompleted) { /* * for loop situation, there will be more than one taskinstance in * jpbm for same node name. We set the start date to null of the * original taskinstance to mark the task has been activited. */ p_taskInstance = WorkflowJbpmUtil.getTaskInstanceByNode(p_processInstance, ((WorkflowTaskInstance) p_nextNodes.getNode(0)).getNodeName()); // WorkflowJbpmUtil.setPrivateValue(p_taskInstance, "start", null); } } /** * Starts the task instance. * * @param p_taskInstance * The task instance. * @param p_assignee * The name of the assignee. */ private void startTaskInstance(TaskInstance p_taskInstance, String p_assignee) { if (p_taskInstance.getStart() == null) { /* * Judges the data of the taskinstance in case of the refresh of the * page. */ p_taskInstance.start(); } p_taskInstance.setActorId(p_assignee); // for GBS-1302, accept interim activity TaskInterimPersistenceAccessor.acceptInterimActivity(p_taskInstance); } // //////////////////////////////////////////////////////////////////// // End: Event notification support // //////////////////////////////////////////////////////////////////// }