/**
* Copyright 2007-2010 非也
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License v3 as published by the Free Software
* Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this library; if not, see http://www.gnu.org/licenses/lgpl.html.
*
*/
package org.fireflow.web_client.app.servlet;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import javax.script.ScriptException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.fireflow.client.WorkflowQuery;
import org.fireflow.client.WorkflowSession;
import org.fireflow.client.WorkflowSessionFactory;
import org.fireflow.client.WorkflowStatement;
import org.fireflow.client.query.Order;
import org.fireflow.client.query.Restrictions;
import org.fireflow.demo.fireflow_ext.WorkflowUtil;
import org.fireflow.engine.context.RuntimeContext;
import org.fireflow.engine.entity.repository.ProcessDescriptorProperty;
import org.fireflow.engine.entity.repository.ProcessRepository;
import org.fireflow.engine.entity.runtime.ActivityInstance;
import org.fireflow.engine.entity.runtime.LocalWorkItem;
import org.fireflow.engine.entity.runtime.ProcessInstance;
import org.fireflow.engine.entity.runtime.WorkItem;
import org.fireflow.engine.entity.runtime.WorkItemProperty;
import org.fireflow.engine.entity.runtime.WorkItemState;
import org.fireflow.engine.entity.runtime.impl.LocalWorkItemImpl;
import org.fireflow.engine.exception.InvalidOperationException;
import org.fireflow.engine.exception.WorkflowProcessNotFoundException;
import org.fireflow.engine.invocation.AssignmentHandler;
import org.fireflow.engine.invocation.impl.AbsServiceInvoker;
import org.fireflow.engine.invocation.impl.DynamicAssignmentHandler;
import org.fireflow.engine.invocation.impl.ReassignmentHandler;
import org.fireflow.engine.modules.loadstrategy.ProcessLoadStrategy;
import org.fireflow.engine.modules.ousystem.Department;
import org.fireflow.engine.modules.ousystem.OUSystemConnector;
import org.fireflow.engine.modules.ousystem.User;
import org.fireflow.engine.modules.ousystem.impl.UserImpl;
import org.fireflow.model.InvalidModelException;
import org.fireflow.model.binding.ServiceBinding;
import org.fireflow.model.servicedef.ServiceDef;
import org.fireflow.pdl.fpdl.misc.FpdlConstants;
import org.fireflow.pdl.fpdl.process.Activity;
import org.fireflow.pdl.fpdl.process.SubProcess;
import org.fireflow.pdl.fpdl.process.WorkflowProcess;
import org.fireflow.service.human.HumanService;
import org.fireflow.web_client.util.Constants;
import org.fireflow.web_client.util.Utils;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* 根据Workitem的信息打开表单,如果WorkItemId为空,表示创建流程实例。
*
* @author 非也 nychen2000@163.com
* Fire Workflow 官方网站:www.firesoa.com 或者 www.fireflow.org
*
*
*/
public class WorkflowOperationServlet extends HttpServlet {
protected WebApplicationContext springCtx = null;
protected RuntimeContext fireContext = null;
protected TransactionTemplate tramsactionTemplate = null;
public void init() throws ServletException {
//准备相关参数及相关spring bean
springCtx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
fireContext = (RuntimeContext)springCtx.getBean(RuntimeContext.Fireflow_Runtime_Context_Name);
tramsactionTemplate = (TransactionTemplate)springCtx.getBean("demoTransactionTemplate");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
this.doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String actionType = req.getParameter(Constants.ACTION_TYPE);
if (Constants.CREATE_PROCESS_INSTANCE.equals(actionType)){
_createProcessInstance(req,resp);
}
else if (Constants.COMPLETE_WORKITEM.equals(actionType)){
_completeWorkItem(req,resp);
}
else if (Constants.LIST_WORKITEMS_IN_PROCESS_INSTANCE.equals(actionType)){
_listWorkItemsInProcessInstance(req,resp);
}
else if (Constants.LIST_MY_ACTIVE_PROCESS_INSTANCE.equals(actionType)){
_listMyActiveProcessInstance(req,resp);
}
else if (Constants.LIST_TODO_WORKITEMS.equals(actionType)){
this._listMyTodoWorkItems(req, resp);
}
else if (Constants.LIST_HAVEDONE_WORKITEMS.equals(actionType)){
this._listMyHaveDoneWorkItems(req, resp);
}
else if (Constants.LIST_READONLY_WORKITEMS.equals(actionType)){
this._listReadOnlyWorkItems(req, resp);
}
else if (Constants.CLAIM_WORKITEM.equals(actionType)){
this._claimWorkItem(req,resp);
}
else if (Constants.DISCLAIM_WORKITEM.equals(actionType)){
this._disclaimWorkItem(req,resp);
}
else if (Constants.OPEN_BIZ_FORM.equals(actionType)){
this._openBizForm(req,resp);
}
else if (Constants.OPEN_NEXT_STEP_ACTOR_SELECTOR.equals(actionType)){
this._openNextStepActorSelector(req,resp);
}
else if (Constants.LOAD_OU_AS_JSTREE_XML.equals(actionType)){
_loadOUAsJstreeXml(req,resp);
}
else if (Constants.OPEN_REASSIGN_ACTOR_SELECTOR.equals(actionType)){
_openReassignActorSelector(req,resp);
}
else if (Constants.REASSIGN_WORKITEM.equals(actionType)){
_reassignWorkItem(req,resp);
}
else if (Constants.OPEN_TARGET_ACTIVITY_SELECTOR.equals(actionType)){
_openTargetActivitySelector(req,resp);
}
else if (Constants.COMPLETE_WORKITEM_AND_JUMP_TO.equals(actionType)){
this._completeWorkItem(req, resp);
}
}
/**
* 为下一个步骤选择操作者
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _openTargetActivitySelector(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String workItemId = req.getParameter(Constants.WORKITEM_ID);
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> workItemQuery = workflowSession.createWorkflowQuery(WorkItem.class);
WorkItem wi = workItemQuery.get(workItemId);
if (wi==null){
forwardToErrorPage(req, resp, "没有找到工作项,workItemId=[" + workItemId
+ "]。", null);
return;
}
if (!(wi instanceof LocalWorkItemImpl)){
forwardToErrorPage(req, resp, "不可以对Remote WorkItem执行签收操作,workItemId=[" + workItemId
+ "]。", null);
return;
}
//1、查找到所有的Activity
//TODO 可以从一个子流程跳转到另外一个子流程吗?
LocalWorkItem workItem = (LocalWorkItem)wi;
ActivityInstance activityInstance = null;//workItem.getActivityInstance();TODO 待修正
WorkflowProcess workflowProcess = null;
try {
workflowProcess = (WorkflowProcess)activityInstance.getWorkflowProcess(workflowSession);
} catch (InvalidModelException e1) {
forwardToErrorPage(req, resp, "查找工作项对应的流程失败[workItemId=" + workItemId
+ "]失败。", e1);
return;
}
List<Activity> allActivities = new ArrayList<Activity>();
List<SubProcess> allLocalSubProcesses = workflowProcess.getLocalSubProcesses();
for (SubProcess subProcess:allLocalSubProcesses){
allActivities.addAll(subProcess.getActivities());
}
Activity activity = (Activity)workflowProcess.findWorkflowElementById(activityInstance.getNodeId());
req.setAttribute("allActivities", allActivities);
req.setAttribute("thisActivity", activity);
//3、跳转到表单页面,让用户补充业务信息
String url = "/fireflow_client/_select_next_activity.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(url);
dispatcher.forward(req, resp);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void _reassignWorkItem(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final String workItemId = req.getParameter(Constants.WORKITEM_ID);
String reassignType = req.getParameter("reassign_flag");
final Map<String,AssignmentHandler> reassignmentHandlers = createReassignmentHandler(req);
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
try{
WorkflowQuery<WorkItem> workItemQuery = workflowSession.createWorkflowQuery(WorkItem.class);
WorkItem wi = workItemQuery.get(workItemId);
if (wi==null){
forwardToErrorPage(req, resp, "没有找到工作项,workItemId=[" + workItemId
+ "]。", null);
return;
}
if (!(wi instanceof LocalWorkItemImpl)){
forwardToErrorPage(req, resp, "不可以对Remote WorkItem执行委派操作,workItemId=[" + workItemId
+ "]。", null);
return;
}
LocalWorkItem workItem = (LocalWorkItem)wi;
ActivityInstance activityInstance = null;//workItem.getActivityInstance();TODO 待修正
final ReassignmentHandler reassignmentHandler = (ReassignmentHandler)reassignmentHandlers.get(activityInstance.getNodeId());
if ("beforeme".equals(reassignType)){
reassignmentHandler.setReassignType(WorkItem.REASSIGN_BEFORE_ME);
}else {
reassignmentHandler.setReassignType(WorkItem.REASSIGN_AFTER_ME);
}
reassignmentHandler.setParentWorkItemId(workItemId);
tramsactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
WorkflowStatement workflowStatement = workflowSession.createWorkflowStatement();
try {
workflowStatement.reassignWorkItemTo(workItemId, reassignmentHandler, null,null,null);
} catch (InvalidOperationException e) {
throw new RuntimeException(e);
}
return null;
}
});
}catch (Exception e) {
forwardToErrorPage(req, resp, "提交流程失败,当前工作项是[workItemId=" + workItemId
+ "]。", e);
return;
}
//3、导航到指定页面,缺省为我的待办页面
String forwardURL = req.getParameter(Constants.FORWARD_URL);
if (forwardURL==null || forwardURL.trim().equals("")){
forwardURL = "/servlet/WorkflowOperationServlet?"+Constants.ACTION_TYPE+"="+Constants.LIST_TODO_WORKITEMS;
}
RequestDispatcher dispatcher = req.getRequestDispatcher(forwardURL);
dispatcher.forward(req, resp);
}
protected void _openReassignActorSelector(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String workItemId = req.getParameter(Constants.WORKITEM_ID);
String reassignFlag = req.getParameter("reassignFlag");
// System.out.println("=========reassignFlag is "+reassignFlag);
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> workItemQuery = workflowSession.createWorkflowQuery(WorkItem.class);
WorkItem wi = workItemQuery.get(workItemId);
if (wi==null){
forwardToErrorPage(req, resp, "没有找到工作项,workItemId=[" + workItemId
+ "]。", null);
return;
}
if (!(wi instanceof LocalWorkItemImpl)){
forwardToErrorPage(req, resp, "不可以对Remote WorkItem执行委派操作,workItemId=[" + workItemId
+ "]。", null);
return;
}
LocalWorkItem workItem = (LocalWorkItem)wi;
ActivityInstance activityInstance = null;//workItem.getActivityInstance();TODO 待修正
req.setAttribute("reassignFlag", reassignFlag);
req.setAttribute("workItem", workItem);
req.setAttribute("activityInstance", activityInstance);
String url = "/fireflow_client/_reassign_actor_selector.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(url);
dispatcher.forward(req, resp);
}
protected void _loadOUAsJstreeXml(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String current_node_id = req.getParameter("current_node_id");
StringBuffer sbuf = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>");
OUSystemConnector ouConnector = fireContext.getEngineModule(OUSystemConnector.class, FpdlConstants.PROCESS_TYPE_FPDL20);
if ("-1".equals(current_node_id)){
List<Department> allTopDeptList = ouConnector.findAllTopDepartments();//查找到所有顶层组织机构,一般情况下只有一条记录
for (Department dept : allTopDeptList){
sbuf.append("<item parent_id=\"").append("0\"")
.append(" id=\"").append(dept.getId()).append("\"")
.append(" state=\"closed\"")
.append(" node_type=\"dept\"")
.append(">\n");
sbuf.append("\t<content>\n");
sbuf.append("\t\t<name><![CDATA[").append(dept.getName()).append("]]></name>\n");
sbuf.append("\t</content>\n");
sbuf.append("</item>");
}
}else{
//下级部门
List<Department> allChildDeptList = ouConnector.findChildDepartments(current_node_id);
for (Department dept : allChildDeptList){
sbuf.append("<item parent_id=\"").append(current_node_id).append("\"")
.append(" id=\"").append(dept.getId()).append("\"")
.append(" state=\"closed\"")
.append(" node_type=\"dept\"")
.append(">\n");
sbuf.append("\t<content>\n");
sbuf.append("\t\t<name><![CDATA[").append(dept.getName()).append("]]></name>\n");
sbuf.append("\t</content>\n");
sbuf.append("</item>");
}
//本部门人员
List<User> allUsers = ouConnector.findUsersInDepartment(current_node_id);
for (User user : allUsers){
sbuf.append("<item parent_id=\"").append(current_node_id).append("\"")
.append(" id=\"").append(user.getId()).append("\"")
.append(" state=\"closed\"")
.append(" node_type=\"user\"")
.append(" name=\"").append(user.getName()).append("\"")
.append(" dept_name=\"").append(user.getDeptName()).append("\"")
.append(" dept_id=\"").append(user.getDeptId()).append("\"")
.append(">\n");
System.out.println("user.getDeptName() is "+user.getDeptName());
sbuf.append("\t<content>\n");
sbuf.append("\t\t<name><![CDATA[").append(user.getName()).append("]]></name>\n");
sbuf.append("\t</content>\n");
sbuf.append("</item>");
}
}
sbuf.append("\n</root>");
String xml = sbuf.toString();
System.out.println(xml);
resp.setContentType("text/xml");
Writer writer = resp.getWriter();
writer.write(xml);
}
/**
* 为下一个步骤选择操作者
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _openNextStepActorSelector(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String workItemId = req.getParameter(Constants.WORKITEM_ID);
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> workItemQuery = workflowSession.createWorkflowQuery(WorkItem.class);
WorkItem wi = workItemQuery.get(workItemId);
if (wi==null){
forwardToErrorPage(req, resp, "没有找到工作项,workItemId=[" + workItemId
+ "]。", null);
return;
}
if (!(wi instanceof LocalWorkItemImpl)){
forwardToErrorPage(req, resp, "不可以对Remote WorkItem执行该操作,workItemId=[" + workItemId
+ "]。", null);
return;
}
LocalWorkItem workItem = (LocalWorkItem)wi;
//1、找到当前Activity的后继Activity
ActivityInstance activityInstance = null;//workItem.getActivityInstance();TODO 待修正
WorkflowProcess workflowProcess = null;
try {
workflowProcess = (WorkflowProcess)activityInstance.getWorkflowProcess(workflowSession);
} catch (InvalidModelException e1) {
forwardToErrorPage(req, resp, "查找工作项对应的流程失败[workItemId=" + workItemId
+ "]失败。", e1);
return;
}
Activity activity = (Activity)workflowProcess.findWorkflowElementById(activityInstance.getNodeId());
if (activity==null){
forwardToErrorPage(req,resp,"流程[processId="+activityInstance.getProcessId()+"]中没有id为"+activityInstance.getNodeId()+"的Activity。",null);
return ;
}
//
List<Activity> nextActivities = activity.getNextActivities();
req.setAttribute("nextActivities", nextActivities);
req.setAttribute("thisActivity", activity);
//2、查询组织机构树
OUSystemConnector ouSystemConnnector = fireContext.getEngineModule(OUSystemConnector.class, activityInstance.getProcessType());
// ouSystemConnnector.
//3、跳转到表单页面,让用户补充业务信息
String url = "/fireflow_client/_next_step_and_actors.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(url);
dispatcher.forward(req, resp);
}
/**
* 打开业务表单
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _openBizForm(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
//1、获得表单URL
String workItemId = req.getParameter(Constants.WORKITEM_ID);
WorkflowQuery<WorkItem> workItemQuery = workflowSession.createWorkflowQuery(WorkItem.class);
WorkItem wi = workItemQuery.get(workItemId);
if (wi==null){
forwardToErrorPage(req, resp, "没有找到工作项,workItemId=[" + workItemId
+ "]。", null);
return;
}
if (!(wi instanceof LocalWorkItemImpl)){
forwardToErrorPage(req, resp, "不可以对Remote WorkItem执行该操作,workItemId=[" + workItemId
+ "]。", null);
return;
}
LocalWorkItem workItem = (LocalWorkItem)wi;
String formURL = workItem.getActionUrl();
//2、获得表单的输入参数,并将参数设置到request attribute
ActivityInstance activityInstance = null;//workItem.getActivityInstance();TODO 待修正
WorkflowProcess workflowProcess = null;
try {
workflowProcess = (WorkflowProcess)activityInstance.getWorkflowProcess(workflowSession);
} catch (InvalidModelException e1) {
forwardToErrorPage(req, resp, "打开工作项的表单失败[workItemId=" + workItemId
+ "]失败。", e1);
return;
}
Activity activity = (Activity)workflowProcess.findWorkflowElementById(activityInstance.getNodeId());
if (activity==null){
forwardToErrorPage(req,resp,"流程[processId="+activityInstance.getProcessId()+"]中没有id为"+activityInstance.getNodeId()+"的Activity。",null);
return ;
}
if (activity.getServiceBinding()==null || activity.getServiceBinding().getServiceId()==null){
forwardToErrorPage(req,resp,"活动[activityId="+activity.getId()+",displayName="+activity.getDisplayName()+"]中没有邦定服务。",null);
return ;
}
final ServiceDef serviceDef = workflowProcess.getService(activity.getServiceBinding().getServiceId());
if (serviceDef==null || !(serviceDef instanceof HumanService)){
forwardToErrorPage(req,resp,"流程[processId="+activityInstance.getProcessId()+"]中没有找到id="+activity.getServiceBinding().getServiceId()+"的服务;或者该服务不是人工任务。",null);
return ;
}
ProcessInstance processInstance = activityInstance.getProcessInstance(workflowSession);
Map<String, Object> theInputValues = null;
try {
theInputValues = AbsServiceInvoker.resolveInputAssignments(fireContext,workflowSession,processInstance,activityInstance,activity.getServiceBinding(),serviceDef);
} catch (ScriptException e) {
forwardToErrorPage(req, resp, "打开工作项的表单失败[workItemId=" + workItemId
+ "]失败。", e);
return;
}
if (theInputValues.size()>0){
Iterator<Entry<String,Object>> iterator = theInputValues.entrySet().iterator();
while (iterator.hasNext()){
Entry<String,Object> entry = iterator.next();
req.setAttribute(entry.getKey(), entry.getValue());
}
}
//3、跳转到表单页面,让用户补充业务信息
RequestDispatcher dispatcher = req.getRequestDispatcher(formURL);
dispatcher.forward(req, resp);
}
/**
* 退签收工作项
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@SuppressWarnings("unchecked")
protected void _disclaimWorkItem(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final String workItemId = req.getParameter(Constants.WORKITEM_ID);
//备注信息
String note = req.getParameter(WorkItemProperty.NOTE.getPropertyName());
if (note==null || note.trim().equals("")){
note = (String)req.getAttribute(WorkItemProperty.NOTE.getPropertyName());
}
if (note==null){
note = "退签收。";
}
final String __note = note;
//1、获得当前系统登录用户并创建Session;系统登录用户必须实现org.fireflow.engine.modules.ousystem.User
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
//2、提交流程
try {
tramsactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
WorkflowStatement stmt = workflowSession
.createWorkflowStatement();
try {
WorkItem result = stmt.disclaimWorkItem(workItemId,null,null,__note);
return result;
} catch (InvalidOperationException e) {
throw new RuntimeException(e);
}
}
});
} catch (Exception e) {
forwardToErrorPage(req, resp, "提交流程失败,当前工作项是[workItemId=" + workItemId
+ "]。", e);
return;
}
//3、导航到指定页面,缺省为我的待办页面
String forwardURL = req.getParameter(Constants.FORWARD_URL);
if (forwardURL==null || forwardURL.trim().equals("")){
forwardURL = "/servlet/WorkflowOperationServlet?"+Constants.ACTION_TYPE+"="+Constants.LIST_TODO_WORKITEMS;
}
RequestDispatcher dispatcher = req.getRequestDispatcher(forwardURL);
dispatcher.forward(req, resp);
}
@SuppressWarnings("unchecked")
protected void _claimWorkItem(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final String workItemId = req.getParameter(Constants.WORKITEM_ID);
//1、获得当前系统登录用户并创建Session;系统登录用户必须实现org.fireflow.engine.modules.ousystem.User
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
//2、提交流程
try {
tramsactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
WorkflowStatement stmt = workflowSession
.createWorkflowStatement();
try {
WorkItem wi = stmt.claimWorkItem(workItemId);
return wi;
} catch (InvalidOperationException e) {
throw new RuntimeException(e);
}
}
});
} catch (Exception e) {
forwardToErrorPage(req, resp, "提交流程失败,当前工作项是[workItemId=" + workItemId
+ "]。", e);
return;
}
//3、导航到指定页面,缺省为我的待办页面
String forwardURL = req.getParameter(Constants.FORWARD_URL);
if (forwardURL==null || forwardURL.trim().equals("")){
forwardURL = "/servlet/WorkflowOperationServlet?"+Constants.ACTION_TYPE+"="+Constants.LIST_TODO_WORKITEMS;
}
RequestDispatcher dispatcher = req.getRequestDispatcher(forwardURL);
dispatcher.forward(req, resp);
}
/**
* 查询抄送信息,
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _listReadOnlyWorkItems(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> query = workflowSession.createWorkflowQuery(WorkItem.class);
query.add(Restrictions.eq(WorkItemProperty.OWNER_ID, u.getId()))
.add(Restrictions.eq(WorkItemProperty.STATE, WorkItemState.READONLY))
.addOrder(Order.desc(WorkItemProperty.CREATED_TIME));
List<WorkItem> workItemList = query.list();
req.setAttribute("workItemList", workItemList);
RequestDispatcher dispatcher = req.getRequestDispatcher("/fireflow_client/my_readonly_workitems.jsp");
dispatcher.forward(req, resp);
}
/**
* 查询当前用户的待办工作项
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _listMyTodoWorkItems(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> query = workflowSession.createWorkflowQuery(WorkItem.class);
query.add(Restrictions.eq(WorkItemProperty.OWNER_ID, u.getId()))
.add(Restrictions.lt(WorkItemProperty.STATE, WorkItemState.DELIMITER))
.addOrder(Order.desc(WorkItemProperty.CREATED_TIME));
List<WorkItem> workItemList = query.list();
req.setAttribute("workItemList", workItemList);
RequestDispatcher dispatcher = req.getRequestDispatcher("/fireflow_client/my_todo_workitems.jsp");
dispatcher.forward(req, resp);
}
/**
* 查询当前用户的已办工作项,此处包含正常完成的,被取消的,委派给他人的等等。
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _listMyHaveDoneWorkItems(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> query = workflowSession.createWorkflowQuery(WorkItem.class);
query.add(Restrictions.eq(WorkItemProperty.OWNER_ID, u.getId()))
.add(Restrictions.gt(WorkItemProperty.STATE, WorkItemState.DELIMITER))
.add(Restrictions.ne(WorkItemProperty.STATE, WorkItemState.READONLY))
.addOrder(Order.desc(WorkItemProperty.END_TIME));
List<WorkItem> workItemList = query.list();
req.setAttribute("workItemList", workItemList);
RequestDispatcher dispatcher = req.getRequestDispatcher("/fireflow_client/my_havedone_workitems.jsp");
dispatcher.forward(req, resp);
}
/**
* 打开当前用户发起的在办流程实例
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _listMyActiveProcessInstance(final HttpServletRequest req, final HttpServletResponse resp)
throws ServletException, IOException {
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> query = workflowSession.createWorkflowQuery(WorkItem.class);
query.add(Restrictions.eq(WorkItemProperty.PROCINST_CREATOR_ID, u.getId()))
.add(Restrictions.lt(WorkItemProperty.STATE, WorkItemState.DELIMITER))
.addOrder(Order.desc(WorkItemProperty.CREATED_TIME));
List<WorkItem> workItemList = query.list();
req.setAttribute("workItemList", workItemList);
RequestDispatcher dispatcher = req.getRequestDispatcher("/fireflow_client/my_active_process_instance.jsp");
dispatcher.forward(req, resp);
}
/**
* 查询同一流程实例的所有工作项
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void _listWorkItemsInProcessInstance(final HttpServletRequest req, final HttpServletResponse resp)
throws ServletException, IOException {
String processInstanceId = req.getParameter(Constants.PROCESS_INSTANCE_ID);
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
WorkflowQuery<WorkItem> query = workflowSession.createWorkflowQuery(WorkItem.class);
query.add(Restrictions.eq(WorkItemProperty.PROCESS_INSTANCE_ID, processInstanceId))
.addOrder(Order.desc(WorkItemProperty.STEP_NUMBER));
List<WorkItem> workItemList = query.list();
req.setAttribute("workItemList", workItemList);
RequestDispatcher dispatcher = req.getRequestDispatcher("/fireflow_client/work_history.jsp");
dispatcher.forward(req, resp);
}
/**
* 结束工作项
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void _completeWorkItem(final HttpServletRequest req, final HttpServletResponse resp)
throws ServletException, IOException {
final String workItemId = req.getParameter(Constants.WORKITEM_ID);
final String targetActivityId = req.getParameter(Constants.TARGET_ACTIVITY_ID);
//获取下一步操作者列表
final Map<String,AssignmentHandler> assignmentHandlers = createAssignmentStrategy(req);
//审批结论、审批意见
String approvalId = req.getParameter(WorkItemProperty.ATTACHMENT_ID.getPropertyName());
if (approvalId==null || approvalId.trim().equals("")){
approvalId = (String)req.getAttribute(WorkItemProperty.ATTACHMENT_ID.getPropertyName());
}
String approvalDetail = req.getParameter(WorkItemProperty.NOTE.getPropertyName());
if (approvalDetail==null || approvalDetail.trim().equals("")){
approvalDetail = (String)req.getAttribute(WorkItemProperty.NOTE.getPropertyName());
}
final String __approvalId = approvalId;
final String __approvalDetail = approvalDetail;
//1、获得当前系统登录用户并创建Session;系统登录用户必须实现org.fireflow.engine.modules.ousystem.User
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory
.createWorkflowSession(fireContext, u);
//2、提交流程
try {
tramsactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
WorkflowStatement stmt = workflowSession
.createWorkflowStatement();
try {
if (targetActivityId == null
|| targetActivityId.trim().equals("")) {
stmt.completeWorkItem(workItemId,
assignmentHandlers,__approvalId,null,__approvalDetail);
} else {
stmt.completeWorkItemAndJumpTo(workItemId,
targetActivityId, assignmentHandlers,__approvalId,null,__approvalDetail);
}
} catch (InvalidOperationException e) {
throw new RuntimeException(e);
}
return null;
}
});
} catch (Exception e) {
forwardToErrorPage(req, resp, "提交流程失败,当前工作项是[workItemId=" + workItemId
+ "]。", e);
return;
}
//3、导航到指定页面,缺省为我的待办页面
String forwardURL = req.getParameter(Constants.FORWARD_URL);
if (forwardURL==null || forwardURL.trim().equals("")){
forwardURL = "/servlet/WorkflowOperationServlet?"+Constants.ACTION_TYPE+"="+Constants.LIST_TODO_WORKITEMS;
}
RequestDispatcher dispatcher = req.getRequestDispatcher(forwardURL);
dispatcher.forward(req, resp);
}
private Map<String,AssignmentHandler> createReassignmentHandler(HttpServletRequest req){
Map<String,AssignmentHandler> assignmentStrategy = new HashMap<String,AssignmentHandler>();
Map<String,List<User>> allActors = new HashMap<String,List<User>>();
Enumeration enumeration = req.getParameterNames();
while(enumeration.hasMoreElements()){
String name = (String)enumeration.nextElement();
if (name!=null && name.startsWith(Constants.NEXT_ACTOR_INPUT_NAME_PREFIX)){
String[] actorsInfo = req.getParameterValues(name);
String activityId = name.substring(Constants.NEXT_ACTOR_INPUT_NAME_PREFIX.length());
List<User> tmpUsers = new ArrayList<User>();
if (actorsInfo!=null && actorsInfo.length>0){
for (String actorInfo : actorsInfo){
User u = parseUser(actorInfo);
tmpUsers.add(u);
}
}
List<User> users = allActors.get(activityId);
if (users==null){
users = new ArrayList<User>();
allActors.put(activityId, users);
}
users.addAll(tmpUsers);
}
}
Iterator<String> keys = allActors.keySet().iterator();
while (keys!=null && keys.hasNext()){
String activityId = keys.next();
List<User> users = allActors.get(activityId);
ReassignmentHandler handler = new ReassignmentHandler();
handler.setPotentialOwners(users);
assignmentStrategy.put(activityId, handler);
//TODO 分配方式待完善
}
return assignmentStrategy;
}
private Map<String,AssignmentHandler> createAssignmentStrategy(HttpServletRequest req){
// String has_customized_actors = req.getParameter(Constants.HAS_CUSTOMIZED_ACTORS);
// if (has_customized_actors!=null && has_customized_actors.trim().equalsIgnoreCase("true")){
Map<String,AssignmentHandler> assignmentStrategy = new HashMap<String,AssignmentHandler>();
Map<String,List<User>> allActors = new HashMap<String,List<User>>();
Enumeration enumeration = req.getParameterNames();
while(enumeration.hasMoreElements()){
String name = (String)enumeration.nextElement();
if (name!=null && name.startsWith(Constants.NEXT_ACTOR_INPUT_NAME_PREFIX)){
String[] actorsInfo = req.getParameterValues(name);
String activityId = name.substring(Constants.NEXT_ACTOR_INPUT_NAME_PREFIX.length());
List<User> tmpUsers = new ArrayList<User>();
if (actorsInfo!=null && actorsInfo.length>0){
for (String actorInfo : actorsInfo){
User u = parseUser(actorInfo);
tmpUsers.add(u);
}
}
List<User> users = allActors.get(activityId);
if (users==null){
users = new ArrayList<User>();
allActors.put(activityId, users);
}
users.addAll(tmpUsers);
}
}
Iterator<String> keys = allActors.keySet().iterator();
while (keys!=null && keys.hasNext()){
String activityId = keys.next();
List<User> users = allActors.get(activityId);
DynamicAssignmentHandler handler = new DynamicAssignmentHandler();
handler.setPotentialOwners(users);
assignmentStrategy.put(activityId, handler);
//TODO 分配方式待完善
}
return assignmentStrategy;
// }
// return null;
}
private User parseUser(String actorInfo){
if (actorInfo==null || actorInfo.trim().length()==0){
return null;
}
UserImpl u = new UserImpl();
StringTokenizer stoken = new StringTokenizer(actorInfo,"~");
if (stoken.hasMoreTokens()){
u.setId(stoken.nextToken());
}
if (stoken.hasMoreTokens()){
u.setName(stoken.nextToken());
}
if (stoken.hasMoreTokens()){
u.setDeptId(stoken.nextToken());
}
if (stoken.hasMoreTokens()){
u.setDeptName(stoken.nextToken());
}
return u;
}
/**
* 创建流程实例,但是并不启动该流程实例
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void _createProcessInstance(final HttpServletRequest req, final HttpServletResponse resp)
throws ServletException, IOException {
final String processId = req.getParameter(Constants.PROCESS_ID);
//1、获得当前系统登录用户并创建Session;系统登录用户必须实现org.fireflow.engine.modules.ousystem.User
final User u = getCurrentUser(req);
final WorkflowSession workflowSession = WorkflowSessionFactory.createWorkflowSession(fireContext, u);
//2、获得流程定义
ProcessLoadStrategy processLoadStrategy = fireContext.getEngineModule(ProcessLoadStrategy.class, FpdlConstants.PROCESS_TYPE_FPDL20);
ProcessRepository tempRepository = null;
try {
User wfUser = workflowSession.getCurrentUser();
tempRepository = processLoadStrategy.findTheProcessForRunning( processId, FpdlConstants.PROCESS_TYPE_FPDL20,wfUser,workflowSession);
} catch (InvalidModelException e1) {
forwardToErrorPage(req,resp,"读取流程定义发生错误,流程id="+processId,e1);
return;
}
final ProcessRepository processRepository = tempRepository;
WorkflowProcess workflowProcess = processRepository==null?null:(WorkflowProcess)processRepository.getProcessObject();
if (workflowProcess==null){
forwardToErrorPage(req,resp,"没有找到相关的流程,流程id="+processId,null);
return;
}
//3、获得起始节点的表单信息
String firstActivityId = req.getParameter(Constants.FIRST_ACTIVITY_ID);
if (firstActivityId==null || firstActivityId.trim().equals("")){
forwardToErrorPage(req,resp,"request参数中没有FIRST_ACTIVITY_ID或者传入的FIRST_ACTIVITY_ID值为空",null);
return ;
}
final Activity activity = workflowProcess.getMainSubProcess().getActivity(firstActivityId);
if (activity==null){
forwardToErrorPage(req,resp,"流程[processId="+processId+"]中没有id为"+firstActivityId+"的Activity。",null);
return ;
}
if (activity.getServiceBinding()==null || activity.getServiceBinding().getServiceId()==null){
forwardToErrorPage(req,resp,"活动[activityId="+activity.getId()+",displayName="+activity.getDisplayName()+"]中没有邦定服务。",null);
return ;
}
final ServiceDef serviceDef = workflowProcess.getService(activity.getServiceBinding().getServiceId());
if (serviceDef==null || !(serviceDef instanceof HumanService)){
forwardToErrorPage(req,resp,"流程[processId="+processId+"]中没有找到id="+activity.getServiceBinding().getServiceId()+"的服务;或者该服务不是人工任务。",null);
return ;
}
HumanService humanService = (HumanService)serviceDef;
String formUrl = humanService.getFormUrl();
//4、创建流程实例(注意,仅是创建,但不启动)
ProcessInstance processInstance = null;
final Map<String,Object> theInputValues = new HashMap<String,Object>();
try {
processInstance = (ProcessInstance) tramsactionTemplate
.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
WorkflowStatement workflowStatement = workflowSession
.createWorkflowStatement();
try {
ProcessInstance processInstance = workflowStatement
.createProcessInstance(
processRepository
.getProcessId(),
processRepository.getVersion());
ServiceBinding serviceBinding = activity.getServiceBinding();
Map<String,Object> inputsValues = AbsServiceInvoker.resolveInputAssignments(fireContext,workflowSession,processInstance,null,serviceBinding,serviceDef);
if (inputsValues!=null){
theInputValues.putAll(inputsValues);
}
return processInstance;
} catch (InvalidModelException e) {
throw new RuntimeException(e);
} catch (WorkflowProcessNotFoundException e) {
throw new RuntimeException(e);
} catch(ScriptException e){
throw new RuntimeException(e);
}
}
});
} catch (Exception e) {
forwardToErrorPage(req, resp, "创建流程实例[processId=" + processId
+ "]失败。", e);
return;
}
//5、设置request attribute
if (theInputValues.size()>0){
Iterator<Entry<String,Object>> iterator = theInputValues.entrySet().iterator();
while (iterator.hasNext()){
Entry<String,Object> entry = iterator.next();
req.setAttribute(entry.getKey(), entry.getValue());
}
}
//6、跳转到表单页面,让用户补充业务信息
req.setAttribute(Constants.PROCESS_INSTANCE_ID, processInstance.getId());
RequestDispatcher dispatcher = req.getRequestDispatcher(formUrl);
dispatcher.forward(req, resp);
}
private void forwardToErrorPage(HttpServletRequest req, HttpServletResponse resp,String message,Throwable exception)
throws ServletException, IOException {
req.setAttribute(Constants.ERROR_MESSAGE, message);
req.setAttribute(Constants.ERROR_STACK, Utils.exceptionStackToString(exception));
RequestDispatcher dispatcher = req.getRequestDispatcher("/common/error_message.jsp");
dispatcher.forward(req, resp);
}
private User getCurrentUser(HttpServletRequest request){
HttpSession session = request.getSession(true);
return WorkflowUtil.getCurrentWorkflowUser(session);
}
}