0001: package org.emforge.jbpm;
0002:
0003: import java.io.ByteArrayInputStream;
0004: import java.io.File;
0005: import java.io.FileNotFoundException;
0006: import java.io.IOException;
0007: import java.io.InputStream;
0008: import java.io.StringWriter;
0009: import java.io.Writer;
0010: import java.util.ArrayList;
0011: import java.util.Collection;
0012: import java.util.Collections;
0013: import java.util.Comparator;
0014: import java.util.Date;
0015: import java.util.Iterator;
0016: import java.util.LinkedList;
0017: import java.util.List;
0018: import java.util.Map;
0019: import java.util.zip.ZipInputStream;
0020:
0021: import javax.jws.WebService;
0022:
0023: import org.acegisecurity.AccessDeniedException;
0024: import org.acegisecurity.userdetails.UserDetails;
0025: import org.apache.commons.collections.CollectionUtils;
0026: import org.apache.commons.lang.ObjectUtils;
0027: import org.apache.commons.lang.StringUtils;
0028: import org.dom4j.DocumentException;
0029: import org.dom4j.DocumentHelper;
0030: import org.dom4j.Element;
0031: import org.dom4j.XPath;
0032: import org.dom4j.xpath.DefaultXPath;
0033: import org.emforge.BpmService;
0034: import org.emforge.EmForgeException;
0035: import org.emforge.comment.CommentTransformer;
0036: import org.emforge.jbpm.messages.TaskStatusRequestEmail;
0037: import org.emforge.jbpm.parser.EmForgeJpdlReader;
0038: import org.emforge.jbpm.web.bean.WorkflowController;
0039: import org.emforge.projectmanager.ProjectService;
0040: import org.emforge.projectmanager.base.MilestoneDO;
0041: import org.emforge.projectmanager.base.ProjectDO;
0042: import org.emforge.projectmanager.base.ProjectRole;
0043: import org.emforge.xfer.CommentTO;
0044: import org.emforge.xfer.HistoryTO;
0045: import org.emforge.xfer.PriorityTO;
0046: import org.emforge.xfer.SelectValueTO;
0047: import org.emforge.xfer.StepTO;
0048: import org.emforge.xfer.TaskStatus;
0049: import org.emforge.xfer.TaskTO;
0050: import org.emforge.xfer.VariableTO;
0051: import org.emforge.xfer.WorkflowTO;
0052: import org.hibernate.Query;
0053: import org.hibernate.Session;
0054: import org.jbpm.JbpmContext;
0055: import org.jbpm.context.def.VariableAccess;
0056: import org.jbpm.context.exe.ContextInstance;
0057: import org.jbpm.db.GraphSession;
0058: import org.jbpm.db.LoggingSession;
0059: import org.jbpm.file.def.FileDefinition;
0060: import org.jbpm.graph.def.Action;
0061: import org.jbpm.graph.def.Event;
0062: import org.jbpm.graph.def.ProcessDefinition;
0063: import org.jbpm.graph.exe.Comment;
0064: import org.jbpm.graph.exe.ProcessInstance;
0065: import org.jbpm.graph.exe.Token;
0066: import org.jbpm.graph.log.ProcessStateLog;
0067: import org.jbpm.logging.exe.LoggingInstance;
0068: import org.jbpm.logging.log.ProcessLog;
0069: import org.jbpm.taskmgmt.def.Task;
0070: import org.jbpm.taskmgmt.exe.SwimlaneInstance;
0071: import org.jbpm.taskmgmt.exe.TaskInstance;
0072: import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
0073: import org.jbpm.taskmgmt.log.TaskAssignLog;
0074: import org.jbpm.util.ClassLoaderUtil;
0075: import org.springframework.beans.BeansException;
0076: import org.springframework.context.ApplicationContext;
0077: import org.springframework.context.ApplicationContextAware;
0078: import org.springframework.core.io.Resource;
0079: import org.springframework.transaction.annotation.Propagation;
0080: import org.springframework.transaction.annotation.Transactional;
0081: import org.springmodules.workflow.jbpm31.JbpmCallback;
0082: import org.springmodules.workflow.jbpm31.JbpmTemplate;
0083:
0084: import ru.emdev.EmForge.EmForgeContext;
0085: import ru.emdev.EmForge.email.EmailSender;
0086: import ru.emdev.EmForge.email.EmailServices;
0087: import ru.emdev.EmForge.email.EmailerException;
0088: import ru.emdev.EmForge.security.EmForgeUserDetails;
0089: import ru.emdev.EmForge.security.UserFactory;
0090: import ru.emdev.EmForge.security.dao.Role;
0091: import ru.emdev.EmForge.security.dao.UserDao;
0092: import ru.emdev.EmForge.security.web.SiteRole;
0093: import ru.emdev.EmForge.util.Helper;
0094:
0095: import com.ecyrd.jspwiki.WikiContext;
0096: import com.ecyrd.jspwiki.WikiEngine;
0097: import com.ecyrd.jspwiki.WikiException;
0098: import com.ecyrd.jspwiki.WikiPage;
0099:
0100: /**
0101: * Implementation for Bpm Web-Service
0102: *
0103: * @author akakunin
0104: */
0105: @WebService(endpointInterface="org.emforge.BpmService")
0106: @Transactional(propagation=Propagation.REQUIRES_NEW,rollbackFor=EmForgeException.class)
0107: public class BpmServiceImpl extends JbpmTemplate implements BpmService,
0108: ApplicationContextAware {
0109:
0110: /** Change to Protected as soon as we will remove old classes */
0111: public static final String COMMENT_FILENAME = "comment.txt";
0112: protected static final String DATE_SEPARATOR = " date:";
0113: protected static final String USER_SEPARATOR = " user:";
0114: protected static final String MESSAGE_SEPARATOR = " message:";
0115:
0116: private ProjectService projectService;
0117: private EmForgeContext emForgeContext;
0118:
0119: // user-factory required to get current user details
0120: private UserFactory userFactory;
0121: private UserDao userDao;
0122:
0123: private EmailServices emailServices;
0124: private ApplicationContext applicationContext;
0125:
0126: private Resource initWorkflowsFolder;
0127:
0128: /**
0129: * @param i_projectService
0130: */
0131: public void setProjectService(ProjectService i_projectService) {
0132:
0133: projectService = i_projectService;
0134: }
0135:
0136: /**
0137: * @param i_userFactory
0138: */
0139: public void setUserFactory(UserFactory i_userFactory) {
0140:
0141: userFactory = i_userFactory;
0142: }
0143:
0144: /**
0145: * @param i_userDao
0146: */
0147: public void setUserDao(UserDao i_userDao) {
0148:
0149: userDao = i_userDao;
0150: }
0151:
0152: /**
0153: * @param i_emForgeContext
0154: */
0155: public void setEmForgeContext(EmForgeContext i_emForgeContext) {
0156:
0157: emForgeContext = i_emForgeContext;
0158: }
0159:
0160: /**
0161: * @param i_emailServices
0162: */
0163: public void setEmailServices(EmailServices i_emailServices) {
0164:
0165: emailServices = i_emailServices;
0166: }
0167:
0168: /**
0169: * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
0170: */
0171: public void setApplicationContext(
0172: ApplicationContext i_applicationContext)
0173: throws BeansException {
0174:
0175: applicationContext = i_applicationContext;
0176: }
0177:
0178: /**
0179: * @param i_initWorkflowsFolder
0180: */
0181: public void setInitWorkflowsFolder(Resource i_initWorkflowsFolder) {
0182:
0183: initWorkflowsFolder = i_initWorkflowsFolder;
0184: }
0185:
0186: /**
0187: * We need to get wikiEngine dinamically, to avoid cyclic references
0188: *
0189: * @return
0190: */
0191: private WikiEngine getWikiEngine() {
0192:
0193: return (WikiEngine) applicationContext.getBean("wikiEngine");
0194: }
0195:
0196: /**
0197: * @see org.springmodules.workflow.jbpm31.JbpmTemplate#afterPropertiesSet()
0198: */
0199: @Override
0200: public void afterPropertiesSet() throws Exception {
0201:
0202: super .afterPropertiesSet();
0203:
0204: // check for workflows, included into distribution and try to install them
0205: if (initWorkflowsFolder != null)
0206: try {
0207: File directory = null;
0208:
0209: try {
0210: directory = initWorkflowsFolder.getFile();
0211: } catch (FileNotFoundException ex) {
0212: // just ignore it here - we simple do not have directory with default processes
0213: }
0214:
0215: if (directory != null) {
0216: String[] files = directory.list();
0217:
0218: for (int i = 0; i < files.length; i++) {
0219: final String fileName = files[i];
0220:
0221: if (fileName.endsWith(".par")) {
0222: final String workflowName = fileName
0223: .substring(0, fileName.length() - 4);
0224:
0225: execute(new JbpmCallback() {
0226:
0227: @SuppressWarnings("unchecked")
0228: public Object doInJbpm(
0229: JbpmContext context) {
0230:
0231: // check is workflow exists
0232: ProcessDefinition processDef = getProcessDef(
0233: context, workflowName,
0234: WORKFLOW_LAST_VERSION);
0235:
0236: if (processDef == null) {
0237: // we do not have workflow with specified name
0238: // so - deploy it
0239: InputStream workflowStream = ClassLoaderUtil
0240: .getStream("processes/"
0241: + fileName);
0242:
0243: try {
0244: deployProcessDef(context,
0245: workflowStream,
0246: "Installed from distribution");
0247: } catch (IOException ex) {
0248: logger
0249: .error(
0250: "Cannot deploy workflow: "
0251: + workflowName,
0252: ex);
0253: // nothing to do - try to deploy next one
0254: }
0255: }
0256: return null;
0257: }
0258: });
0259: }
0260: }
0261: }
0262: } catch (Exception ex) {
0263: logger.error("Cannot initialize default workflows", ex);
0264: }
0265: }
0266:
0267: //
0268: // web-service implementation
0269: //
0270:
0271: /**
0272: * Returns List of Active Tasks for Logged-In user for Specified Project
0273: *
0274: * @param projectName
0275: * @return
0276: */
0277: @SuppressWarnings("unchecked")
0278: public List<StepTO> getActiveSteps(String i_projectName)
0279: throws EmForgeException {
0280:
0281: // check - is project exists
0282: if (!StringUtils.isEmpty(i_projectName)
0283: && projectService.getProject(i_projectName) == null) {
0284: throw new EmForgeException("Project \"" + i_projectName
0285: + "\" not found");
0286: }
0287:
0288: // get project
0289: final ProjectDO project = StringUtils.isEmpty(i_projectName) ? null
0290: : projectService.getProject(i_projectName);
0291:
0292: // get current user
0293: final UserDetails currentUser = userFactory.getCurrentUser();
0294:
0295: // get list of active tasks for user
0296: List<StepTO> steps = (List<StepTO>) execute(new JbpmCallback() {
0297:
0298: @SuppressWarnings("unchecked")
0299: public Object doInJbpm(JbpmContext context) {
0300:
0301: Session session = context.getSession();
0302: assert session != null;
0303:
0304: Query query = session
0305: .getNamedQuery("TaskListBean.findActiveTasks");
0306: assert query != null;
0307:
0308: if (currentUser != null) {
0309: query.setString("actorId", currentUser
0310: .getUsername());
0311: } else {
0312: query.setString("actorId", "");
0313: }
0314: Long projectId = (project == null) ? Long.valueOf(-1)
0315: : project.getId();
0316: query.setParameter("projectId", projectId);
0317: List<TaskInstance> activeTasks = query.list();
0318:
0319: // create result
0320: Collection<StepTO> outputCollection = new StepCollection(
0321: activeTasks, new TaskTransformer(
0322: projectService, userFactory));
0323:
0324: return outputCollection;
0325: }
0326: });
0327:
0328: return steps;
0329: }
0330:
0331: /**
0332: * Returns Specific Step by ID
0333: *
0334: * @param stepId - step to return
0335: * @return step object, or null if nothing found
0336: */
0337: public StepTO getStep(final long stepId) throws EmForgeException {
0338:
0339: StepTO step = (StepTO) execute(new JbpmCallback() {
0340:
0341: @SuppressWarnings("unchecked")
0342: public Object doInJbpm(JbpmContext context) {
0343:
0344: TaskInstance task = context.getTaskInstance(stepId);
0345:
0346: if (task == null) {
0347: return null;
0348: }
0349:
0350: return new TaskTransformer(projectService, userFactory)
0351: .transform(task);
0352: }
0353: });
0354:
0355: if (!canReadTask(step.getTaskId())) {
0356: throw new AccessDeniedException(
0357: "You are not allowed to view this task");
0358: }
0359:
0360: return step;
0361: }
0362:
0363: /**
0364: * Returns Specific Task by ID
0365: *
0366: * @param taskId - task to return
0367: * @return task object, or null if nothing found
0368: */
0369: public TaskTO getTask(final long taskId) throws EmForgeException {
0370:
0371: final ProcessTransformer processTransformer = new ProcessTransformer(
0372: this , projectService, userFactory, getWikiEngine(),
0373: true);
0374: TaskTO task = (TaskTO) execute(new JbpmCallback() {
0375:
0376: @SuppressWarnings("unchecked")
0377: public Object doInJbpm(JbpmContext context) {
0378:
0379: ProcessInstance process = context
0380: .getProcessInstance(taskId);
0381:
0382: if (process == null) {
0383: return null;
0384: }
0385:
0386: return processTransformer.transform(process);
0387: }
0388: });
0389:
0390: if (task != null && !canReadTask(task.getId())) {
0391: throw new AccessDeniedException(
0392: "You are not allowed to view this task");
0393: }
0394:
0395: return task;
0396: }
0397:
0398: /**
0399: * @see org.emforge.BpmService#hasTask(long)
0400: */
0401: public Boolean hasTask(final long taskId) {
0402:
0403: Boolean hasTask = (Boolean) execute(new JbpmCallback() {
0404:
0405: @SuppressWarnings("unchecked")
0406: public Object doInJbpm(JbpmContext context) {
0407:
0408: ProcessInstance process = context
0409: .getProcessInstance(taskId);
0410:
0411: if (process == null) {
0412: return false;
0413: } else {
0414: return true;
0415: }
0416: }
0417: });
0418:
0419: return hasTask;
0420: }
0421:
0422: /**
0423: * Return workflow by name and version
0424: *
0425: * @param name - name of workflow
0426: * @param version - version. If -1 is used - means last version of specified workflow
0427: * @return Workflow object for specified name and version. Null is not found
0428: */
0429: public WorkflowTO getWorkflowByName(final String i_name,
0430: final int i_version) throws EmForgeException {
0431:
0432: WorkflowTO workflow = (WorkflowTO) execute(new JbpmCallback() {
0433:
0434: public Object doInJbpm(JbpmContext context) {
0435:
0436: ProcessDefinition processDef = getProcessDef(context,
0437: i_name, i_version);
0438:
0439: if (processDef == null) {
0440: return null;
0441: }
0442:
0443: ProcessDefTransformer processDefTransformer = new ProcessDefTransformer(
0444: getWikiEngine(), context);
0445:
0446: return processDefTransformer.transform(processDef);
0447: }
0448: });
0449:
0450: return workflow;
0451: }
0452:
0453: /**
0454: * @see org.emforge.BpmService#hasWorkflow(java.lang.String, int)
0455: */
0456: public Boolean hasWorkflow(final String i_name, final int i_version) {
0457:
0458: Boolean hasWorkflow = (Boolean) execute(new JbpmCallback() {
0459:
0460: public Object doInJbpm(JbpmContext context) {
0461:
0462: ProcessDefinition processDef = getProcessDef(context,
0463: i_name, i_version);
0464:
0465: if (processDef == null) {
0466: return false;
0467: } else {
0468: return true;
0469: }
0470: }
0471: });
0472:
0473: return hasWorkflow;
0474: }
0475:
0476: /**
0477: * Return workflow by id
0478: *
0479: * @param workflowId - id of workflow
0480: * @return Workflow object for specified id. Null is not found
0481: */
0482: public WorkflowTO getWorkflowById(final long i_workflowId)
0483: throws EmForgeException {
0484:
0485: WorkflowTO workflow = (WorkflowTO) execute(new JbpmCallback() {
0486:
0487: public Object doInJbpm(JbpmContext context) {
0488:
0489: ProcessDefinition processDef = context
0490: .getGraphSession().getProcessDefinition(
0491: i_workflowId);
0492:
0493: if (processDef == null) {
0494: return null;
0495: }
0496:
0497: // convert processDef into workflow
0498: ProcessDefTransformer processDefTransformer = new ProcessDefTransformer(
0499: getWikiEngine(), context);
0500:
0501: return processDefTransformer.transform(processDef);
0502: }
0503: });
0504:
0505: return workflow;
0506: }
0507:
0508: /**
0509: * Return list of Workflows, stored in the system
0510: *
0511: * @return
0512: */
0513: @SuppressWarnings("unchecked")
0514: public WorkflowTO[] getWorkflows() throws EmForgeException {
0515:
0516: List<WorkflowTO> workflows = (List<WorkflowTO>) execute(new JbpmCallback() {
0517:
0518: public Object doInJbpm(JbpmContext context) {
0519:
0520: ProcessDefTransformer processDefTransformer = new ProcessDefTransformer(
0521: getWikiEngine(), context);
0522:
0523: List<WorkflowTO> workflows = new LinkedList<WorkflowTO>();
0524:
0525: /*
0526: * List<ProcessDefinition> processDefinitions =
0527: * context.getSession().getNamedQuery("ProcessDefListBean.findLastProcessDefinitions").list();
0528: */
0529: Session dbSession = context.getSession();
0530: GraphSession gSession = new GraphSession(dbSession);
0531: List<ProcessDefinition> processDefinitions = gSession
0532: .findLatestProcessDefinitions();
0533:
0534: CollectionUtils.collect(processDefinitions,
0535: processDefTransformer, workflows);
0536:
0537: // sort workflows by Start Task Name
0538: Collections.sort(workflows,
0539: new Comparator<WorkflowTO>() {
0540:
0541: public int compare(WorkflowTO workflow1,
0542: WorkflowTO workflow2) {
0543:
0544: if (workflow1 == null
0545: && workflow2 == null) {
0546: return 0;
0547: } else if (workflow1 == null) {
0548: return -1;
0549: } else if (workflow2 == null) {
0550: return 1;
0551: } else {
0552: return workflow1
0553: .getStartName()
0554: .compareTo(
0555: workflow2
0556: .getStartName());
0557: }
0558: }
0559: });
0560:
0561: return workflows;
0562: }
0563: });
0564:
0565: return workflows.toArray(new WorkflowTO[workflows.size()]);
0566: }
0567:
0568: /**
0569: * Retunrs history for workflow versions
0570: *
0571: * @param name - workflow name to get history
0572: * @param version - workflow version to get history
0573: * @return
0574: * @throws EmForgeException
0575: */
0576: public HistoryTO[] getWorkflowHistory(final String i_name,
0577: final int i_version) {
0578:
0579: HistoryTO[] result = (HistoryTO[]) execute(new JbpmCallback() {
0580:
0581: @SuppressWarnings("unchecked")
0582: public Object doInJbpm(JbpmContext context) {
0583:
0584: List<ProcessDefinition> processDefs = context
0585: .getGraphSession()
0586: .findAllProcessDefinitionVersions(i_name);
0587: List<HistoryTO> history = new LinkedList<HistoryTO>();
0588:
0589: // transform process defs into history elements
0590: CollectionUtils.collect(processDefs,
0591: new ProcessDefToHistoryTransformer(
0592: getWikiEngine(), emForgeContext),
0593: history);
0594:
0595: return history.toArray(new HistoryTO[history.size()]);
0596: }
0597: });
0598:
0599: return result;
0600: }
0601:
0602: /**
0603: * @see org.emforge.BpmService#getUsedWorkflows(java.lang.String, int)
0604: */
0605: public WorkflowTO[] getUsedWorkflows(final String name,
0606: final int version) throws EmForgeException {
0607:
0608: Object result = execute(new JbpmCallback() {
0609:
0610: @SuppressWarnings("unchecked")
0611: public Object doInJbpm(JbpmContext context) {
0612:
0613: ProcessDefinition processDef = getProcessDef(context,
0614: name, version);
0615:
0616: if (processDef == null) {
0617: return new EmForgeException(
0618: "Cannot find specified workflow");
0619: }
0620:
0621: Session session = context.getSession();
0622: assert session != null;
0623:
0624: Query query = session
0625: .getNamedQuery("JbpmProcessDefImpl.findSubProcesses");
0626: assert query != null;
0627:
0628: query.setLong("processDefId", processDef.getId());
0629:
0630: List<ProcessDefinition> subProcesses = query.list();
0631:
0632: // now select all late-binded names
0633: query = session
0634: .getNamedQuery("JbpmProcessDefImpl.findSubProcessNames");
0635: assert query != null;
0636:
0637: query.setLong("processDefId", processDef.getId());
0638: List<String> lateBindedNames = query.list();
0639:
0640: // now add late-binded processDefs into list
0641: for (String lateBindedName : lateBindedNames) {
0642: boolean found = false;
0643: // is it already exists?
0644: for (ProcessDefinition subProcDef : subProcesses) {
0645: if (subProcDef.equals(lateBindedName)) {
0646: found = true;
0647: break;
0648: }
0649: }
0650:
0651: if (!found) {
0652: subProcesses.add(context.getGraphSession()
0653: .findLatestProcessDefinition(
0654: lateBindedName));
0655: }
0656: }
0657:
0658: List<WorkflowTO> workflows = new LinkedList<WorkflowTO>();
0659: ProcessDefTransformer transformer = new ProcessDefTransformer(
0660: getWikiEngine(), context);
0661:
0662: CollectionUtils.collect(subProcesses, transformer,
0663: workflows);
0664:
0665: return workflows.toArray(new WorkflowTO[workflows
0666: .size()]);
0667: }
0668: });
0669:
0670: if (result instanceof EmForgeException) {
0671: throw (EmForgeException) result;
0672: }
0673:
0674: return (WorkflowTO[]) result;
0675: }
0676:
0677: /**
0678: * Returns Blocking Steps for specified Task
0679: */
0680: @SuppressWarnings("unchecked")
0681: public StepTO[] getBlockingSteps(final long i_taskId)
0682: throws EmForgeException {
0683:
0684: if (!canReadTask(i_taskId)) {
0685: throw new AccessDeniedException(
0686: "You are not allowed to view this task");
0687: }
0688:
0689: List<StepTO> blockingSteps = (List<StepTO>) execute(new JbpmCallback() {
0690:
0691: @SuppressWarnings("unchecked")
0692: public Object doInJbpm(JbpmContext context) {
0693:
0694: List<StepTO> result = new LinkedList<StepTO>();
0695:
0696: // get process
0697: ProcessInstance process = context
0698: .getProcessInstance(i_taskId);
0699:
0700: if (process == null) {
0701: return result;
0702: }
0703:
0704: // get blocking tasks for process
0705: Collection<TaskInstance> blockingTasks = getBlockingTasks(process);
0706:
0707: // convert it to StepTO
0708: CollectionUtils
0709: .collect(blockingTasks, new TaskTransformer(
0710: projectService, userFactory), result);
0711:
0712: return result;
0713: }
0714: });
0715:
0716: return blockingSteps.toArray(new StepTO[blockingSteps.size()]);
0717: }
0718:
0719: /**
0720: * Add comment for specified Task
0721: *
0722: * @return created Comment object
0723: */
0724: public Boolean addComment(final long i_taskId,
0725: final String i_comment) throws EmForgeException {
0726:
0727: if (!canCommentTask(i_taskId)) {
0728: throw new AccessDeniedException(
0729: "You are not allowed to add comment for this task");
0730: }
0731:
0732: Boolean result = (Boolean) execute(new JbpmCallback() {
0733:
0734: @SuppressWarnings("unchecked")
0735: public Object doInJbpm(JbpmContext context) {
0736:
0737: if (StringUtils.isNotBlank(i_comment)) {
0738: // get process
0739: ProcessInstance process = context
0740: .getProcessInstance(i_taskId);
0741:
0742: if (process == null) {
0743: return false;
0744: }
0745:
0746: process.getRootToken().addComment(i_comment);
0747: }
0748:
0749: return true;
0750: }
0751: });
0752:
0753: return result;
0754: }
0755:
0756: /**
0757: * Returns Comments for Specified Task
0758: *
0759: * @param taskId - id of task we need to get comments
0760: * @return array of task comments
0761: */
0762: @SuppressWarnings("unchecked")
0763: public CommentTO[] getTaskComments(final long i_taskId)
0764: throws EmForgeException {
0765:
0766: if (!canReadTask(i_taskId)) {
0767: throw new AccessDeniedException(
0768: "You are not allowed to view this task");
0769: }
0770:
0771: List<Comment> comments = (List<Comment>) execute(new JbpmCallback() {
0772:
0773: @SuppressWarnings("unchecked")
0774: public Object doInJbpm(JbpmContext context) {
0775:
0776: List<Comment> result = new ArrayList<Comment>();
0777:
0778: // get process
0779: ProcessInstance process = context
0780: .getProcessInstance(i_taskId);
0781:
0782: if (process == null) {
0783: return result;
0784: }
0785:
0786: addComments(process.getRootToken(), result);
0787:
0788: // sort comments according to date
0789: Collections.sort(result, new Comparator<Comment>() {
0790:
0791: public int compare(Comment o1, Comment o2) {
0792:
0793: // [AKA] I meet here very stupid exception
0794: // seems Timestamp.comparyTo cannot be called with simple Date
0795: // as argument
0796: // but in my case once it happend (one time was timestamp and
0797: // another just date
0798: // return o1.getTime().compareTo(o2.getTime());
0799:
0800: int value = o2.getTime()
0801: .compareTo(o1.getTime());
0802:
0803: if (value > 0) {
0804: return -1;
0805: } else if (value < 0) {
0806: return 1;
0807: } else {
0808: return 0;
0809: }
0810: }
0811: });
0812:
0813: return result;
0814: }
0815: });
0816:
0817: // now, transform jbpm Comments to CommentTO
0818: CommentTransformer transformer = new JbpmCommentTransformer(
0819: getWikiEngine(), String.valueOf(i_taskId));
0820: Collection<CommentTO> outputCollection = new LinkedList<CommentTO>();
0821: CollectionUtils
0822: .collect(comments, transformer, outputCollection);
0823:
0824: // return result
0825: return outputCollection.toArray(new CommentTO[outputCollection
0826: .size()]);
0827: }
0828:
0829: /**
0830: * Add new workflow
0831: *
0832: * @param workflowContent - content of par-file
0833: * @param comment - comment for this deployment
0834: * @return create workflow
0835: */
0836: public WorkflowTO addNewWorkflow(final byte[] i_workflowContent,
0837: final String comment) throws EmForgeException {
0838:
0839: if (!canAddNewWorkflow()) {
0840: throw new AccessDeniedException(
0841: "You are not allowed to add workflows");
0842: }
0843:
0844: WorkflowTO workflow = (WorkflowTO) execute(new JbpmCallback() {
0845:
0846: public Object doInJbpm(JbpmContext context) {
0847:
0848: ProcessDefinition processDefinition = null;
0849: try {
0850: InputStream is = new ByteArrayInputStream(
0851: i_workflowContent);
0852:
0853: processDefinition = deployProcessDef(context, is,
0854: comment);
0855: } catch (IOException ioEx) {
0856: logger.info("Cannot Deploy Process", ioEx);
0857: return null;
0858: }
0859:
0860: ProcessDefTransformer transformer = new ProcessDefTransformer(
0861: getWikiEngine(), context);
0862: return transformer.transform(processDefinition);
0863: }
0864: });
0865:
0866: return workflow;
0867: }
0868:
0869: /**
0870: * Returns start step for specified workflow. It is "empty" task - it's id is null since it is not created. It
0871: * should be used for filling required variables and any other required information, getting information about
0872: * transition, and starting new task later with passing this step back
0873: *
0874: * @param name - started workflow name
0875: * @param version - started workflow version
0876: * @param projectName - name of project, for which workflow is created
0877: * @return
0878: */
0879: @SuppressWarnings("unchecked")
0880: public StepTO getWorkflowStartStep(final String i_name,
0881: final int i_version, final String i_projectName)
0882: throws EmForgeException {
0883:
0884: Object result = execute(new JbpmCallback() {
0885:
0886: public Object doInJbpm(JbpmContext context) {
0887:
0888: // get workflow
0889: ProcessDefinition processDef = getProcessDef(context,
0890: i_name, i_version);
0891:
0892: if (processDef == null) {
0893: return new EmForgeException(
0894: "Cano find specified workflow");
0895: }
0896:
0897: Task startTask = processDef.getProcessDefinition()
0898: .getTaskMgmtDefinition().getStartTask();
0899: TaskDefinitionTransformer transformer = new TaskDefinitionTransformer(
0900: projectService, userFactory, i_projectName);
0901:
0902: return transformer.transform(startTask);
0903: }
0904: });
0905:
0906: if (result instanceof EmForgeException) {
0907: throw (EmForgeException) result;
0908: }
0909:
0910: return (StepTO) result;
0911: }
0912:
0913: /**
0914: * Starts new task
0915: *
0916: * @param startStep - information about started task like: priority, variable values, required by start task,
0917: * dueDate and so on
0918: * @param transitionName - name of transition, should be used for completing start-task
0919: * @param tempPageName - in case then description and attachments was specified for task, they were stored in
0920: * temporare Wiki-Page. this param contains name of this page May be empty
0921: * @todo tempPageName should be passed n startStep (somehow), and this method should receive content for description
0922: * @return created task
0923: */
0924: public TaskTO startTask(final StepTO i_startStep,
0925: final String i_transitionName, final String i_tempPageName)
0926: throws EmForgeException {
0927:
0928: final BpmServiceImpl bpmService = this ;
0929:
0930: // check - is used allowed to start new task
0931: if (!canStartNewTask(i_startStep.getProjectName())) {
0932: throw new AccessDeniedException(
0933: "You are not allowed to start new task");
0934: }
0935:
0936: Object result = execute(new JbpmCallback() {
0937:
0938: public Object doInJbpm(JbpmContext context) {
0939:
0940: Object proc = startTaskImpl(context, i_startStep,
0941: i_transitionName, i_tempPageName);
0942:
0943: if (proc instanceof EmForgeException) {
0944: return proc;
0945: }
0946:
0947: // now, convert
0948: ProcessTransformer transformer = new ProcessTransformer(
0949: bpmService, projectService, userFactory,
0950: getWikiEngine(), true);
0951:
0952: return transformer.transform(proc);
0953: }
0954:
0955: });
0956:
0957: if (result instanceof EmForgeException) {
0958: throw (EmForgeException) result;
0959: }
0960:
0961: TaskTO createdTask = (TaskTO) result;
0962: return createdTask;
0963: }
0964:
0965: /**
0966: * Stop Specified Task
0967: *
0968: * @param taskId - id of task we need to stop
0969: * @param comment - comment specified why task is stopped (may be empty)
0970: * @return true is task stopped, othervise false
0971: */
0972: public Boolean stopTask(final long i_taskId, String i_comment)
0973: throws EmForgeException {
0974:
0975: TaskTO task = getTask(i_taskId);
0976:
0977: if (!canStopTask(task)) {
0978: throw new AccessDeniedException(
0979: "You are not allowed to stop this task");
0980: }
0981:
0982: if (i_comment != null) {
0983: addComment(i_taskId, i_comment);
0984: }
0985:
0986: // now, stop the process
0987: Object result = execute(new JbpmCallback() {
0988:
0989: public Object doInJbpm(JbpmContext context) {
0990:
0991: // get process instance
0992: ProcessInstance process = context
0993: .getProcessInstance(i_taskId);
0994:
0995: if (process == null) {
0996: return new EmForgeException("Cannot find task #"
0997: + i_taskId);
0998: }
0999:
1000: if (process.getEnd() != null) {
1001: return new EmForgeException("Task #" + i_taskId
1002: + " already finished");
1003: }
1004:
1005: process.end();
1006:
1007: // stops all blocking tasks
1008: // It should be done authomatically, but according to bugs:
1009: // http://jira.jboss.com/jira/browse/JBPM-392 and
1010: // http://jira.jboss.com/jira/browse/JBPM-590 it will be fixed only in
1011: // 3.2
1012: // so, until this time we should do it by our selves
1013: // [AKA: Mar 11, 2008] According to comments in these bugs - it is never will be fixed.
1014: Collection<TaskInstance> blockingTasks = getBlockingTasks(process);
1015: for (TaskInstance task : blockingTasks) {
1016: task.setEnd(new Date());
1017: }
1018:
1019: return null;
1020: }
1021: });
1022:
1023: if (result instanceof EmForgeException) {
1024: throw (EmForgeException) result;
1025: }
1026:
1027: return true;
1028: }
1029:
1030: /**
1031: * Save task
1032: *
1033: * @param task - task to be saved with all required variables set
1034: * @param comment - comment related to changes
1035: * @return - true if saving success
1036: * @throws EmForgeException
1037: */
1038: public Boolean saveTask(final TaskTO i_task, String i_comment)
1039: throws EmForgeException {
1040:
1041: if (!canChangeTask(i_task)) {
1042: throw new AccessDeniedException(
1043: "You are not allowed to change this task");
1044: }
1045:
1046: if (i_comment != null) {
1047: addComment(i_task.getId(), i_comment);
1048: }
1049:
1050: Object result = execute(new JbpmCallback() {
1051:
1052: public Object doInJbpm(JbpmContext context) {
1053:
1054: // try to find task instance
1055: ProcessInstance processInstance = context
1056: .getProcessInstance(i_task.getId());
1057:
1058: if (processInstance == null) {
1059: return new EmForgeException("Cannot find task #"
1060: + i_task.getId());
1061: }
1062:
1063: // now, fill this process instance with all passed variables
1064: for (VariableTO var : i_task.getVariables()) {
1065: if (!BpmVariable.MILESTONE.getVariable().equals(
1066: var.getLabel())) {
1067: setVariable(processInstance, var.getLabel(),
1068: var.getValue());
1069: } else {
1070: // special processing for milestone
1071: // @todo It is better to avoid such convertion and store milestone and project references as
1072: // names, not as ID
1073: MilestoneDO milestone = projectService
1074: .getMilestone(var.getValue());
1075: setVariable(processInstance, var.getLabel(),
1076: milestone);
1077: }
1078:
1079: // is it one of "ASSIGN_TO" variables?
1080: if (Role.isVariableName(var.getLabel())
1081: && !BpmSystemRole.isSystemRole(var
1082: .getLabel())) {
1083: // in this case we should set same value into swimlane instance (if it is exists)
1084: SwimlaneInstance si = null;
1085: String roleName = Role
1086: .getRoleNameFromVariableName(var
1087: .getLabel());
1088: if (roleName != null) {
1089: si = processInstance.getTaskMgmtInstance()
1090: .getSwimlaneInstance(roleName);
1091: }
1092:
1093: if (si != null) {
1094: // here we should check - if value is empty - that means swimlane has no any assignment
1095: // we should set swimlane name itself as swimlane assignment - so, later, it will be copied
1096: // into taskInstance
1097: if (StringUtils.isEmpty(ObjectUtils
1098: .toString(var.getValue()))) {
1099: si.setActorId(roleName);
1100: } else {
1101: si.setActorId(ObjectUtils.toString(var
1102: .getValue()));
1103: }
1104: }
1105: }
1106: }
1107:
1108: // save title, priority and dueDate
1109: setVariable(processInstance, BpmVariable.TITLE
1110: .getVariable(), i_task.getTitle());
1111: setVariable(processInstance, BpmVariable.DUEDATE
1112: .getVariable(), i_task.getDueDate());
1113: setPriority(processInstance, i_task.getPriority()
1114: .getValue());
1115:
1116: // save start variable
1117: context.save(processInstance);
1118:
1119: return null;
1120: }
1121: });
1122:
1123: if (result instanceof EmForgeException) {
1124: throw (EmForgeException) result;
1125: }
1126:
1127: return true;
1128: }
1129:
1130: /**
1131: * Assign step to new owner
1132: *
1133: * @param stepId
1134: * @param newActor
1135: * @param comment
1136: * @return
1137: * @throws EmForgeException
1138: */
1139: public StepTO assignStep(final StepTO i_step,
1140: final String i_newActor, String i_comment)
1141: throws EmForgeException {
1142:
1143: if (!canChangeStep(i_step)) {
1144: throw new AccessDeniedException(
1145: "You are not allowed to change this step");
1146: }
1147:
1148: if (i_comment != null) {
1149: addComment(i_step.getTaskId(), i_comment);
1150: }
1151:
1152: Object result = execute(new JbpmCallback() {
1153:
1154: public Object doInJbpm(JbpmContext context) {
1155:
1156: // try to find task instance
1157: TaskInstance taskInstance = context
1158: .getTaskInstance(i_step.getId());
1159:
1160: if (taskInstance.getSwimlaneInstance() != null) {
1161: String swimlaneName = taskInstance
1162: .getSwimlaneInstance().getName();
1163: String varName = Role.getVariableName(swimlaneName);
1164:
1165: // set variable in step
1166: if (taskInstance.getVariable(varName) != null) {
1167: taskInstance.setVariable(varName, i_newActor);
1168: }
1169:
1170: // also set variable in process instance
1171: ProcessInstance processInstance = taskInstance
1172: .getToken().getProcessInstance();
1173: setVariable(processInstance, varName, i_newActor);
1174: }
1175:
1176: i_step.setActor(i_newActor);
1177: // set new actor and override swimlane value
1178: taskInstance.setActorId(i_newActor, true);
1179:
1180: // save start variable
1181: context.save(taskInstance);
1182:
1183: return i_step;
1184: }
1185: });
1186:
1187: if (result instanceof EmForgeException) {
1188: throw (EmForgeException) result;
1189: }
1190:
1191: return i_step;
1192: }
1193:
1194: /**
1195: * Change Step Priority
1196: *
1197: * @param step
1198: * @param newPriority
1199: * @param comment
1200: * @return
1201: * @throws EmForgeException
1202: */
1203: public StepTO changeStepPriority(final StepTO i_step,
1204: final PriorityTO i_newPriority, String i_comment)
1205: throws EmForgeException {
1206:
1207: if (!canChangeStep(i_step)) {
1208: throw new AccessDeniedException(
1209: "You are not allowed to change this step");
1210: }
1211:
1212: if (i_comment != null) {
1213: addComment(i_step.getTaskId(), i_comment);
1214: }
1215:
1216: i_step.setPriority(i_newPriority);
1217:
1218: Object result = execute(new JbpmCallback() {
1219:
1220: public Object doInJbpm(JbpmContext context) {
1221:
1222: // try to find task instance
1223: TaskInstance taskInstance = context
1224: .getTaskInstance(i_step.getId());
1225:
1226: // change priority
1227: taskInstance.setPriority(i_step.getPriority()
1228: .getValue());
1229:
1230: // save start variable
1231: context.save(taskInstance);
1232: return i_step;
1233: }
1234: });
1235:
1236: if (result instanceof EmForgeException) {
1237: throw (EmForgeException) result;
1238: }
1239:
1240: return i_step;
1241: }
1242:
1243: /**
1244: * Complete step
1245: *
1246: * @param step - step to be completed with all required variables set
1247: * @param transitionName - transaction name, should be used for completion
1248: * @param comment - comment related to completion
1249: * @return - new state of Task processed
1250: * @throws EmForgeException
1251: */
1252: public TaskTO completeStep(final StepTO i_step,
1253: final String i_transitionName, final String i_comment)
1254: throws EmForgeException {
1255:
1256: if (!canCompleteStep(i_step)) {
1257: throw new AccessDeniedException(
1258: "You are not allowed to complete this task");
1259: }
1260:
1261: final BpmServiceImpl bpmService = this ;
1262:
1263: if (i_comment != null) {
1264: addComment(i_step.getTaskId(), i_comment);
1265: }
1266:
1267: Object result = execute(new JbpmCallback() {
1268:
1269: public Object doInJbpm(JbpmContext context) {
1270:
1271: // try to find task instance
1272: TaskInstance taskInstance = context
1273: .getTaskInstance(i_step.getId());
1274:
1275: if (taskInstance == null) {
1276: return new EmForgeException("Cannot find step #"
1277: + i_step.getId());
1278: }
1279:
1280: ProjectDO project = ProcessTransformer
1281: .getProject(taskInstance.getToken()
1282: .getProcessInstance());
1283:
1284: // check input variables
1285: String message = checkVariables(i_step, taskInstance
1286: .getTask(), project.getName());
1287: if (message != null) {
1288: return new EmForgeException(message);
1289: }
1290:
1291: // now, fill this task instance with all passed variables
1292: setVariables(context, taskInstance, i_step);
1293:
1294: try {
1295: // save start variable
1296: context.save(taskInstance);
1297:
1298: // now, we need complete start task with specified transition
1299: closeTask(context, taskInstance, i_transitionName);
1300: } catch (Exception ex) {
1301: return new EmForgeException("Cannot complete step",
1302: ex);
1303: }
1304:
1305: // now, we need to convert our process instance into task TO and return it
1306: // first of all - flush session and refresh object
1307: context.getSession().flush();
1308: context.getSession().refresh(
1309: taskInstance.getToken().getProcessInstance());
1310:
1311: // now, convert
1312: ProcessTransformer transformer = new ProcessTransformer(
1313: bpmService, projectService, userFactory,
1314: getWikiEngine(), true);
1315:
1316: return transformer.transform(taskInstance.getToken()
1317: .getProcessInstance());
1318: }
1319: });
1320:
1321: if (result instanceof EmForgeException) {
1322: throw (EmForgeException) result;
1323: }
1324:
1325: return (TaskTO) result;
1326: }
1327:
1328: /**
1329: * Returns list of currently active subtasks for specified task
1330: *
1331: * @param taskId - parent task id
1332: * @return list of active sub-tasks
1333: */
1334: public TaskTO[] getBlockingSubTasks(final long taskId)
1335: throws EmForgeException {
1336:
1337: if (!canReadTask(taskId)) {
1338: throw new AccessDeniedException(
1339: "You are not allowed to read this task");
1340: }
1341:
1342: final BpmServiceImpl bpmService = this ;
1343:
1344: Object result = execute(new JbpmCallback() {
1345:
1346: @SuppressWarnings("unchecked")
1347: public Object doInJbpm(JbpmContext context) {
1348:
1349: // try to find process instance
1350: ProcessInstance processInstance = context
1351: .getProcessInstance(taskId);
1352:
1353: if (processInstance == null) {
1354: return new EmForgeException("Cannot find task #"
1355: + taskId);
1356: }
1357:
1358: List<ProcessInstance> blockingProcesses = getBlockingSubProcesses(
1359: context, processInstance);
1360:
1361: // now transform to collection of TaskTO
1362: ProcessTransformer transformer = new ProcessTransformer(
1363: bpmService, projectService, userFactory,
1364: getWikiEngine(), false);
1365: List<TaskTO> blockingTasks = new LinkedList<TaskTO>();
1366: CollectionUtils.collect(blockingProcesses, transformer,
1367: blockingTasks);
1368:
1369: return blockingTasks.toArray(new TaskTO[blockingTasks
1370: .size()]);
1371: }
1372: });
1373:
1374: if (result instanceof EmForgeException) {
1375: throw (EmForgeException) result;
1376: }
1377:
1378: return (TaskTO[]) result;
1379: }
1380:
1381: /**
1382: * Returns list of finished subtasks for specified task
1383: *
1384: * @param taskId - parent task id
1385: * @return list of finished sub-tasks
1386: */
1387: public TaskTO[] getFinishedSubTasks(final long taskId)
1388: throws EmForgeException {
1389:
1390: if (!canReadTask(taskId)) {
1391: throw new AccessDeniedException(
1392: "You are not allowed to read this task");
1393: }
1394:
1395: final BpmServiceImpl bpmService = this ;
1396:
1397: Object result = execute(new JbpmCallback() {
1398:
1399: @SuppressWarnings("unchecked")
1400: public Object doInJbpm(JbpmContext context) {
1401:
1402: // try to find process instance
1403: ProcessInstance processInstance = context
1404: .getProcessInstance(taskId);
1405:
1406: if (processInstance == null) {
1407: return new EmForgeException("Cannot find task #"
1408: + taskId);
1409: }
1410:
1411: List<ProcessInstance> finishedProcesses = new LinkedList<ProcessInstance>();
1412:
1413: Token rootToken = processInstance.getRootToken();
1414:
1415: getFinishedSubProcessesFromToken(context, rootToken,
1416: finishedProcesses);
1417:
1418: // additionally get subprocesses from TasSubProcesses table
1419: Session session = context.getSession();
1420: assert session != null;
1421:
1422: Query query = session
1423: .getNamedQuery("JbpmProcessImpl.findFinishedSubProcesses");
1424: assert query != null;
1425:
1426: query.setLong("processId", processInstance.getId());
1427: List<ProcessInstance> subProcesses = query.list();
1428:
1429: // merge both
1430: finishedProcesses.addAll(subProcesses);
1431:
1432: // now transform to collection of TaskTO
1433: ProcessTransformer transformer = new ProcessTransformer(
1434: bpmService, projectService, userFactory,
1435: getWikiEngine(), false);
1436: List<TaskTO> finishedTasks = new LinkedList<TaskTO>();
1437: CollectionUtils.collect(finishedProcesses, transformer,
1438: finishedTasks);
1439:
1440: return finishedTasks.toArray(new TaskTO[finishedTasks
1441: .size()]);
1442: }
1443: });
1444:
1445: if (result instanceof EmForgeException) {
1446: throw (EmForgeException) result;
1447: }
1448:
1449: return (TaskTO[]) result;
1450: }
1451:
1452: /**
1453: * Create subtask for specified step
1454: *
1455: * @param stepId - step used as parent for subtask
1456: * @param name - name of workflow used for starting task
1457: * @param version - version of workflow, used to start
1458: * @return
1459: * @throws EmForgeException
1460: */
1461: public TaskTO startSubTask(final long i_parentStepId,
1462: final StepTO i_startStep, final String i_transitionName,
1463: final String i_tempPageName) throws EmForgeException {
1464:
1465: if (!canStartNewTask(i_startStep.getProjectName())) {
1466: throw new AccessDeniedException(
1467: "You are not allowed to start new task");
1468: }
1469:
1470: final BpmServiceImpl bpmService = this ;
1471:
1472: Object result = execute(new JbpmCallback() {
1473:
1474: public Object doInJbpm(JbpmContext context) {
1475:
1476: // get the task instance
1477: TaskInstance taskInstance = context
1478: .getTaskInstance(i_parentStepId);
1479: if (taskInstance == null) {
1480: return new EmForgeException("Cannot find step #"
1481: + i_parentStepId);
1482: }
1483:
1484: Object obj = startTaskImpl(context, i_startStep,
1485: i_transitionName, i_tempPageName);
1486:
1487: if (obj instanceof EmForgeException) {
1488: return obj;
1489: }
1490:
1491: ProcessInstance subProc = (ProcessInstance) obj;
1492:
1493: TaskSubProcess taskSubProcess = new TaskSubProcess(
1494: taskInstance, subProc);
1495: // save it
1496: context.getSession().saveOrUpdate(taskSubProcess);
1497:
1498: // now, convert
1499: ProcessTransformer transformer = new ProcessTransformer(
1500: bpmService, projectService, userFactory,
1501: getWikiEngine(), true);
1502:
1503: return transformer.transform(subProc);
1504: }
1505: });
1506:
1507: if (result instanceof EmForgeException) {
1508: throw (EmForgeException) result;
1509: }
1510:
1511: return (TaskTO) result;
1512: }
1513:
1514: /**
1515: * Get task history
1516: *
1517: * @param taskId - task id to get history
1518: * @return
1519: * @throws EmForgeException
1520: */
1521: public HistoryTO[] getTaskHistory(final long taskId)
1522: throws EmForgeException {
1523:
1524: if (!canReadTask(taskId)) {
1525: throw new AccessDeniedException(
1526: "You are not allowed to read this task");
1527: }
1528:
1529: Object result = execute(new JbpmCallback() {
1530:
1531: @SuppressWarnings("unchecked")
1532: public Object doInJbpm(JbpmContext context) {
1533:
1534: // get process instance
1535: ProcessInstance process = context
1536: .getProcessInstance(taskId);
1537:
1538: if (process == null) {
1539: return new EmForgeException("Cannot find task #"
1540: + taskId);
1541: }
1542:
1543: LoggingSession logSession = context.getLoggingSession();
1544: // TODO currently we getting logs only by ROOT token.
1545: // later we will need implement for child tokens too
1546: Collection<ProcessLog> logs = logSession
1547: .findLogsByToken(process.getRootToken().getId());
1548: List<HistoryTO> history = new LinkedList<HistoryTO>();
1549: ProcessLogTransformer transformer = new ProcessLogTransformer(
1550: emForgeContext, taskId);
1551:
1552: for (ProcessLog processLog : logs) {
1553: if (processLog
1554: .getClass()
1555: .equals(
1556: org.jbpm.graph.log.ProcessInstanceCreateLog.class)
1557: || processLog
1558: .getClass()
1559: .equals(
1560: org.jbpm.graph.log.ProcessInstanceEndLog.class)
1561: || processLog
1562: .getClass()
1563: .equals(
1564: org.jbpm.taskmgmt.log.TaskEndLog.class)) {
1565: history.add(transformer.transform(processLog));
1566: }
1567: }
1568:
1569: return history.toArray(new HistoryTO[history.size()]);
1570: }
1571: });
1572:
1573: if (result instanceof EmForgeException) {
1574: throw (EmForgeException) result;
1575: }
1576:
1577: return (HistoryTO[]) result;
1578: }
1579:
1580: /**
1581: * Is it possible for currently logged user request a status for specified step
1582: *
1583: * @param stepId - step id to check
1584: * @return true if it is possible to request status
1585: * @throws EmForgeException
1586: */
1587: public Boolean isPossibleRequestStatus(final long stepId)
1588: throws EmForgeException {
1589:
1590: // anonymous cannot request status
1591: if (userFactory.getCurrentUser().isAnonymous()) {
1592: return false;
1593: }
1594:
1595: Object result = execute(new JbpmCallback() {
1596:
1597: @SuppressWarnings("unchecked")
1598: public Object doInJbpm(JbpmContext context) {
1599:
1600: // try to get task instance
1601: TaskInstance taskInstance = context
1602: .getTaskInstance(stepId);
1603: if (taskInstance == null) {
1604: return new EmForgeException("Cannot find step #"
1605: + stepId);
1606: }
1607:
1608: // is owner of step - same user as currently logged?
1609: if (userFactory.getCurrentUser().getUsername().equals(
1610: taskInstance.getActorId())) {
1611: return false;
1612: }
1613:
1614: String email = getTaskOwnerEmail(taskInstance);
1615: if (email == null) {
1616: // there is no email to send request
1617: return false;
1618: }
1619:
1620: return true;
1621: }
1622: });
1623:
1624: if (result instanceof EmForgeException) {
1625: throw (EmForgeException) result;
1626: }
1627:
1628: return (Boolean) result;
1629: }
1630:
1631: /**
1632: * Request status for specified step
1633: *
1634: * @param stepId - step to request
1635: * @param request - request message
1636: * @return
1637: * @throws EmForgeException
1638: */
1639: public Boolean requestStatus(final long stepId, final String request)
1640: throws EmForgeException {
1641:
1642: if (!isPossibleRequestStatus(stepId)) {
1643: return false;
1644: }
1645:
1646: Object result = execute(new JbpmCallback() {
1647:
1648: @SuppressWarnings("unchecked")
1649: public Object doInJbpm(JbpmContext context) {
1650:
1651: // try to get task instance
1652: TaskInstance taskInstance = context
1653: .getTaskInstance(stepId);
1654: if (taskInstance == null) {
1655: return new EmForgeException("Cannot find step #"
1656: + stepId);
1657: }
1658: // convert it into StepTO
1659: TaskTransformer taskTransformer = new TaskTransformer(
1660: projectService, userFactory);
1661: StepTO step = taskTransformer.transform(taskInstance);
1662:
1663: EmForgeUserDetails fromUser = userFactory
1664: .getCurrentUser();
1665: String toEmail = getTaskOwnerEmail(taskInstance);
1666:
1667: logger.info("Send status request email from "
1668: + fromUser.getUsername() + " to " + toEmail);
1669:
1670: // create task bean
1671: TaskStatusRequestEmail message = (TaskStatusRequestEmail) emailServices
1672: .getEmailFactory().createEmail(
1673: "taskstatusrequest");
1674:
1675: message.setTask(step);
1676: message.setMessage(request);
1677:
1678: // Set up the email
1679: message.setPriority(EmailSender.PRIORITY_NORMAL);
1680:
1681: message.setSubject("Status Request For Task : \""
1682: + step.getTitle() + "\"");
1683:
1684: message.setToName(toEmail);
1685: message.setFromName(fromUser.getEmail());
1686:
1687: // send message
1688: try {
1689: emailServices.getEmailSender().sendMessage(message);
1690:
1691: return true;
1692: } catch (EmailerException ex) {
1693: // process error:
1694: // print error message
1695: logger.error(
1696: "Cannot send task status request to email "
1697: + toEmail, ex);
1698:
1699: return false;
1700: }
1701: }
1702: });
1703:
1704: if (result instanceof EmForgeException) {
1705: throw (EmForgeException) result;
1706: }
1707:
1708: return (Boolean) result;
1709: }
1710:
1711: /**
1712: * Find tasks We will have reporting service, allowed us to generate reports for any criteria. But - we will need
1713: * also some easy-reporting - there we will able find and display list of tasks This is initial version of method,
1714: * implemented this 'easy-reporting' it's interface will be changed in future to support more options for search
1715: *
1716: * @param milestoneName -
1717: * @param status
1718: * @param includeSubTasks
1719: * @return
1720: */
1721: @SuppressWarnings("unchecked")
1722: public List<TaskTO> findTasks(String i_milestoneName,
1723: final TaskStatus i_status, final boolean i_includeSubTasks)
1724: throws EmForgeException {
1725:
1726: final MilestoneDO milestone = i_milestoneName == null ? null
1727: : projectService.getMilestone(i_milestoneName);
1728: final BpmServiceImpl bpmService = this ;
1729:
1730: if (milestone == null) {
1731: throw new EmForgeException(
1732: "Only search by milestones supported for now");
1733: }
1734:
1735: Object result = execute(new JbpmCallback() {
1736:
1737: @SuppressWarnings("unchecked")
1738: public Object doInJbpm(JbpmContext context) {
1739:
1740: Session dbSession = context.getSession();
1741: Query query = null;
1742:
1743: if (i_status == TaskStatus.OPENED) {
1744: if (i_includeSubTasks) {
1745: query = dbSession
1746: .getNamedQuery("Milestone.findOpenedProcesses");
1747: } else {
1748: query = dbSession
1749: .getNamedQuery("Milestone.findOpenedProcessesExceptSubprocesses");
1750: }
1751: } else {
1752: if (i_includeSubTasks) {
1753: query = dbSession
1754: .getNamedQuery("Milestone.findClosedProcesses");
1755: } else {
1756: query = dbSession
1757: .getNamedQuery("Milestone.findClosedProcessesExceptSubprocesses");
1758: }
1759: }
1760:
1761: query.setLong("milestoneId", milestone.getId());
1762: List<ProcessInstance> processes = query.list();
1763:
1764: // convert it to TO
1765: ProcessTransformer transformer = new ProcessTransformer(
1766: bpmService, projectService, userFactory,
1767: getWikiEngine(), false);
1768: List<TaskTO> tasks = new TaskCollection(processes,
1769: transformer);
1770:
1771: return tasks;
1772: }
1773: });
1774:
1775: if (result instanceof EmForgeException) {
1776: throw (EmForgeException) result;
1777: }
1778: return (List<TaskTO>) result;
1779: }
1780:
1781: //
1782: // Security Checks
1783: //
1784:
1785: /**
1786: * is current user allowed to read specified task Currently anybody can see any task
1787: *
1788: * @param stepId
1789: * @return
1790: */
1791: public boolean canReadTask(long stepId) {
1792:
1793: return true;
1794: }
1795:
1796: /**
1797: * is current user allowed to complete specified step
1798: *
1799: * @param stepId
1800: * @return
1801: */
1802: public boolean canCompleteStep(StepTO step) {
1803:
1804: if (step == null) {
1805: return false;
1806: }
1807:
1808: return isStepOwner(step) || isGroupMember(step)
1809: || isProjectManager(step.getProjectName()) || isAdmin();
1810: }
1811:
1812: /**
1813: * Is Current User allowed to edit task description
1814: *
1815: * @param taskId
1816: * @return
1817: */
1818: public boolean canEditTaskDescription(TaskTO task) {
1819:
1820: if (task == null) {
1821: return false;
1822: }
1823:
1824: return (isTaskOwner(task)
1825: || isProjectManager(task.getProjectName()) || isAdmin())
1826: && !task.getHasEnded();
1827: }
1828:
1829: /**
1830: * Is Current user allowed to add attachment for task
1831: *
1832: * @param taskId
1833: * @return
1834: */
1835: public boolean canAddAttachment(long taskId) {
1836:
1837: return !userFactory.getCurrentUser().isAnonymous();
1838: }
1839:
1840: /**
1841: * Is current user allowed to add comment for the task
1842: *
1843: * @param taskId
1844: * @return
1845: */
1846: public boolean canCommentTask(long taskId) {
1847:
1848: return !userFactory.getCurrentUser().isAnonymous();
1849: }
1850:
1851: /**
1852: * Is current user allowed to close the specified task
1853: *
1854: * @param taskId
1855: * @return
1856: */
1857: public boolean canStopTask(TaskTO task) {
1858:
1859: if (task == null) {
1860: return false;
1861: }
1862:
1863: return (isTaskOwner(task)
1864: || isProjectManager(task.getProjectName()) || isAdmin())
1865: && !task.getHasEnded();
1866: }
1867:
1868: /**
1869: * Is current user allowed to change the task
1870: *
1871: * @param taskId
1872: * @return
1873: */
1874: public boolean canChangeTask(TaskTO task) {
1875:
1876: if (task == null) {
1877: return false;
1878: }
1879:
1880: return (isTaskOwner(task)
1881: || isProjectManager(task.getProjectName()) || isAdmin())
1882: && !task.getHasEnded();
1883: }
1884:
1885: /**
1886: * Is current user allowed to change the step
1887: *
1888: * @param stepId
1889: * @return
1890: */
1891: public boolean canChangeStep(StepTO step) {
1892:
1893: if (step == null) {
1894: return false;
1895: }
1896:
1897: return isStepOwner(step) || isGroupMember(step)
1898: || isProjectManager(step.getProjectName()) || isAdmin();
1899: }
1900:
1901: /**
1902: * Is Current user allowed to reassign the steps for specified task
1903: *
1904: * @param stepId
1905: * @return
1906: */
1907: public boolean canReassignSteps(TaskTO task) {
1908:
1909: if (task == null) {
1910: return false;
1911: }
1912:
1913: return (isProjectManager(task.getProjectName()) || isAdmin())
1914: && !task.getHasEnded();
1915: }
1916:
1917: /**
1918: * Is current user allowed to add new workflows
1919: *
1920: * @return
1921: */
1922: public boolean canAddNewWorkflow() {
1923:
1924: return isAdmin();
1925: }
1926:
1927: /**
1928: * Is Current user allowed to start new tasks for specified project
1929: *
1930: * @param projectName
1931: * @return
1932: */
1933: public boolean canStartNewTask(String projectName) {
1934:
1935: // currently logged-in user allowed to start task for any project
1936: return !userFactory.getCurrentUser().isAnonymous();
1937: }
1938:
1939: //
1940: // Utility Functions
1941: //
1942:
1943: /**
1944: * @param i_process
1945: * @return
1946: */
1947: protected TaskInstance getParentTask(final ProcessInstance i_process) {
1948:
1949: TaskInstance task = (TaskInstance) execute(new JbpmCallback() {
1950:
1951: @SuppressWarnings("unchecked")
1952: public Object doInJbpm(JbpmContext context) {
1953:
1954: Query query = context.getSession().getNamedQuery(
1955: "JbpmProcessImpl.findSuperTask");
1956: query.setLong("processId", i_process.getId());
1957:
1958: List<TaskInstance> super Tasks = query.list();
1959:
1960: if (super Tasks.size() > 0) {
1961: // get first task
1962: TaskInstance super Task = super Tasks.iterator()
1963: .next();
1964: return super Task;
1965: }
1966:
1967: return null;
1968: }
1969: });
1970:
1971: return task;
1972: }
1973:
1974: /**
1975: * @param process
1976: * @return
1977: */
1978: @SuppressWarnings("unchecked")
1979: protected Date getLastProcessChangesDate(
1980: final ProcessInstance process) {
1981:
1982: Map<Token, List<ProcessLog>> logMap = (Map<Token, List<ProcessLog>>) execute(new JbpmCallback() {
1983:
1984: public Object doInJbpm(JbpmContext context) {
1985:
1986: LoggingSession logSession = context.getLoggingSession();
1987: return logSession.findLogsByProcessInstance(process
1988: .getId());
1989: }
1990: });
1991:
1992: // currently get logs only for root token
1993: // we cannot use Collection here due to reason that we need last log
1994: List<ProcessLog> logs = (List<ProcessLog>) logMap.get(process
1995: .getRootToken());
1996:
1997: if (logs.size() == 0) {
1998: return null;
1999: }
2000:
2001: ProcessLog log = (ProcessLog) logs.get(logs.size() - 1);
2002: return log.getDate();
2003: }
2004:
2005: /**
2006: * Get List of Blocking tasks for Process
2007: */
2008: static protected Collection<TaskInstance> getBlockingTasks(
2009: ProcessInstance process) {
2010:
2011: // get the root token
2012: Token rootToken = process.getRootToken();
2013:
2014: LinkedList<TaskInstance> blockingTasks = new LinkedList<TaskInstance>();
2015:
2016: getBlockingTasksFromToken(rootToken, blockingTasks);
2017:
2018: return blockingTasks;
2019: }
2020:
2021: /**
2022: * @param i_token
2023: * @param o_blockingTasks
2024: */
2025: @SuppressWarnings("unchecked")
2026: static private void getBlockingTasksFromToken(Token i_token,
2027: Collection<TaskInstance> o_blockingTasks) {
2028:
2029: Map children = i_token.getChildren();
2030: if (children != null && children.size() > 0) {
2031: Collection childTokens = children.values();
2032: for (Iterator iterator = childTokens.iterator(); iterator
2033: .hasNext();) {
2034: Token child = (Token) iterator.next();
2035: getBlockingTasksFromToken(child, o_blockingTasks);
2036: }
2037: }
2038:
2039: TaskMgmtInstance tmi = i_token.getProcessInstance()
2040: .getTaskMgmtInstance();
2041: assert tmi != null;
2042:
2043: Collection<TaskInstance> unfinishedTasks = tmi
2044: .getUnfinishedTasks(i_token);
2045:
2046: for (TaskInstance task : unfinishedTasks) {
2047: o_blockingTasks.add(task);
2048: }
2049: }
2050:
2051: /**
2052: * @param process
2053: * @return
2054: */
2055: @SuppressWarnings("unchecked")
2056: protected Collection<TaskInstance> getAllBlockers(
2057: final ProcessInstance process) {
2058:
2059: Collection<TaskInstance> blockers = (Collection<TaskInstance>) execute(new JbpmCallback() {
2060:
2061: public Object doInJbpm(JbpmContext context) {
2062:
2063: Collection<TaskInstance> result = getBlockingTasks(process);
2064:
2065: for (ProcessInstance subProcess : getBlockingSubProcesses(
2066: context, process)) {
2067: result.addAll(getBlockingTasks(subProcess));
2068: }
2069:
2070: return result;
2071: }
2072: });
2073:
2074: return blockers;
2075: }
2076:
2077: /**
2078: * @param i_token
2079: * @param o_result
2080: */
2081: @SuppressWarnings("unchecked")
2082: private void addComments(Token i_token, Collection<Comment> o_result) {
2083:
2084: // add comments from currently processed token
2085: if (i_token.getComments() != null) {
2086: o_result.addAll(i_token.getComments());
2087: }
2088:
2089: // process all subtokens
2090: // for fixing #3317 - seems sometimes i_token.getChildren returns null
2091: if (i_token.getChildren() != null
2092: && i_token.getChildren().values() != null) {
2093: Iterator iter = i_token.getChildren().values().iterator();
2094: while (iter.hasNext()) {
2095: Token subToken = (Token) iter.next();
2096: addComments(subToken, o_result);
2097: }
2098: }
2099: }
2100:
2101: /**
2102: * Closed task instance with specified transition and returned next task instance, in case, then it is assigned to
2103: * same user
2104: *
2105: * @param context
2106: * @param task
2107: * @param i_transitionName
2108: * @return
2109: */
2110: private TaskInstance closeTask(JbpmContext context,
2111: TaskInstance task, String i_transitionName) {
2112:
2113: String taskActor = task.getActorId();
2114:
2115: LoggingInstance loggingInstance = task.getContextInstance()
2116: .getProcessInstance().getLoggingInstance();
2117:
2118: // Sometimes we can make several assignments during one request
2119: // for example then we create new process - fist we create
2120: // start task, fill it wil values
2121: // and then close it - in this case this value will be not 0
2122: // but 1 - or probubly more
2123: int assignmentsBefore = loggingInstance.getLogs(
2124: TaskAssignLog.class).size();
2125:
2126: // end processing task
2127: if (StringUtils.isEmpty(i_transitionName)) {
2128: task.end();
2129: } else {
2130: task.end(i_transitionName);
2131: }
2132:
2133: context.save(task);
2134:
2135: // see how many tasks were assigned after finishing this task.
2136: // if only one task was assigned to same user - we will
2137: // automatically
2138: // open task-window for this task
2139: List<?> assignmentLogs = loggingInstance
2140: .getLogs(TaskAssignLog.class);
2141:
2142: if (assignmentLogs.size() - assignmentsBefore == 1) {
2143: // only one new task was assigned
2144: TaskAssignLog assignLog = (TaskAssignLog) assignmentLogs
2145: .get(assignmentsBefore);
2146: assert assignLog != null;
2147:
2148: String assignedTo = assignLog.getTaskNewActorId();
2149: TaskInstance nextTask = assignLog.getTaskInstance();
2150:
2151: // and it was assigned to the same actor as current task
2152: if (taskActor != null && taskActor.equals(assignedTo)) {
2153: // return this next task
2154: return nextTask;
2155: }
2156: }
2157:
2158: // return null
2159: return null;
2160:
2161: }
2162:
2163: /**
2164: * Checks the variables, passed in step - is all required variables specified?
2165: *
2166: * @param step - step passsed into service
2167: * @param task - related task definition
2168: * @return null if everything ok, othervise returns error message
2169: */
2170: private String checkVariables(StepTO step, Task task,
2171: String projectName) {
2172:
2173: // in any case - title should not be empty!
2174: if (StringUtils.isEmpty(step.getTitle())) {
2175: return "Task Title cannot be empty!";
2176: }
2177:
2178: List<VariableAccess> writableVariables = TaskDefinitionTransformer
2179: .getWritableVariables(task);
2180:
2181: for (VariableAccess variable : writableVariables) {
2182: // variable requried - check what it is specified!
2183: VariableTO var = step.getVariable(variable.getMappedName());
2184:
2185: if (variable.isRequired()) {
2186: if (var == null || StringUtils.isEmpty(var.getValue())) {
2187: return "Value for variable \""
2188: + variable.getMappedName()
2189: + "\" should be specified";
2190: }
2191: }
2192:
2193: // for variables, has selectValues - check - is specified value included into them
2194: VariableTransformer transformer = new VariableTransformer(
2195: projectService, userFactory, null, projectName);
2196:
2197: SelectValueTO[] selectValues = transformer
2198: .getVarSelectValues(variable.getMappedName());
2199:
2200: // is select Values specified?
2201: if (selectValues != null && selectValues.length > 0
2202: && var != null) {
2203:
2204: // try to find assigned to var value in these selectValues
2205: Boolean valueFound = false;
2206: for (SelectValueTO selectValue : selectValues) {
2207: if (StringUtils.equals(var.getValue(), selectValue
2208: .getValue())) {
2209: valueFound = true;
2210: break;
2211: }
2212: }
2213:
2214: // is found?
2215: if (!valueFound) {
2216: // no - error
2217: return "Incorrect value specified for variable "
2218: + var.getDisplayLabel();
2219: }
2220: }
2221: }
2222:
2223: return null;
2224: }
2225:
2226: /**
2227: * Copy Variables from Step to TaskInstance
2228: *
2229: * @param i_context
2230: * @param i_taskInstance
2231: * @param i_step
2232: */
2233: private void setVariables(JbpmContext i_context,
2234: TaskInstance i_taskInstance, StepTO i_step) {
2235:
2236: for (VariableTO var : i_step.getWritableVariables()) {
2237: if (!BpmVariable.MILESTONE.getVariable().equals(
2238: var.getLabel())) {
2239: i_taskInstance.setVariable(var.getLabel(), var
2240: .getValue());
2241: } else {
2242: // special processing for milestone
2243: // @todo It is better to avoid such convertion and store milestone and project references as names, not
2244: // as ID
2245: MilestoneDO milestone = projectService.getMilestone(var
2246: .getValue());
2247: i_taskInstance.setVariable(var.getLabel(), milestone);
2248: }
2249:
2250: // is it one of "ASSIGN_TO" variables?
2251: if (Role.isVariableName(var.getLabel())
2252: && !BpmSystemRole.isSystemRole(var.getLabel())) {
2253: // in this case we should set same value into swimlane instance (if it is exists)
2254: SwimlaneInstance si = null;
2255: String roleName = Role.getRoleNameFromVariableName(var
2256: .getLabel());
2257: if (roleName != null) {
2258: si = i_taskInstance.getTaskMgmtInstance()
2259: .getSwimlaneInstance(roleName);
2260: }
2261:
2262: if (si != null) {
2263: // here we should check - if value is empty - that means swimlane has no any assignment
2264: // we should set swimlane name itself as swimlane assignment - so, later, it will be copied into
2265: // taskInstance
2266: if (StringUtils.isEmpty(ObjectUtils.toString(var
2267: .getValue()))) {
2268: si.setActorId(roleName);
2269: } else {
2270: si.setActorId(ObjectUtils.toString(var
2271: .getValue()));
2272: }
2273: }
2274: }
2275: }
2276: }
2277:
2278: /**
2279: * Returns list of blocking subprocess instances
2280: *
2281: * @param context
2282: * @param processInstance
2283: * @return
2284: */
2285: @SuppressWarnings("unchecked")
2286: static protected List<ProcessInstance> getBlockingSubProcesses(
2287: JbpmContext context, ProcessInstance processInstance) {
2288:
2289: List<ProcessInstance> blockingProcesses = new LinkedList<ProcessInstance>();
2290:
2291: Token rootToken = processInstance.getRootToken();
2292:
2293: getBlockingSubProcessesFromToken(rootToken, blockingProcesses);
2294:
2295: // additionally get subprocesses from TasSubProcesses table
2296: Session session = context.getSession();
2297: assert session != null;
2298:
2299: Query query = session
2300: .getNamedQuery("JbpmProcessImpl.findSubProcesses");
2301: assert query != null;
2302:
2303: query.setLong("processId", processInstance.getId());
2304: List<ProcessInstance> subProcesses = query.list();
2305:
2306: // merge both
2307: blockingProcesses.addAll(subProcesses);
2308: return blockingProcesses;
2309: }
2310:
2311: /**
2312: * Returns list of blocking subprocesses for specified token
2313: *
2314: * @param i_token
2315: * @param o_blockingSubProcesses
2316: */
2317: @SuppressWarnings("unchecked")
2318: static private void getBlockingSubProcessesFromToken(Token i_token,
2319: Collection<ProcessInstance> o_blockingSubProcesses) {
2320:
2321: Map<?, Token> children = i_token.getChildren();
2322: if (children != null && children.size() > 0) {
2323: Collection<Token> childTokens = children.values();
2324: for (Token child : childTokens) {
2325: getBlockingSubProcessesFromToken(child,
2326: o_blockingSubProcesses);
2327: }
2328: }
2329:
2330: ProcessInstance subProcess = i_token.getSubProcessInstance();
2331: if (subProcess != null) {
2332: o_blockingSubProcesses.add(subProcess);
2333: }
2334: }
2335:
2336: /**
2337: * Returns list of finished subprocesses for specified token
2338: *
2339: * @param i_token
2340: * @param o_finishedSubProcesses
2341: */
2342: @SuppressWarnings("unchecked")
2343: private void getFinishedSubProcessesFromToken(JbpmContext context,
2344: Token i_token,
2345: Collection<ProcessInstance> o_finishedSubProcesses) {
2346:
2347: Map<?, Token> children = i_token.getChildren();
2348: if (children != null && children.size() > 0) {
2349: Collection<Token> childTokens = children.values();
2350: for (Token child : childTokens) {
2351: getBlockingSubProcessesFromToken(child,
2352: o_finishedSubProcesses);
2353: }
2354: }
2355:
2356: // @todo
2357: // it seems we should get this information from history
2358: // but in my test I did not found any ProcessState log entry
2359: // need to investigate more
2360: LoggingSession logSession = context.getLoggingSession();
2361: List<ProcessLog> logs = logSession.findLogsByToken(i_token
2362: .getId());
2363:
2364: for (ProcessLog log : logs) {
2365: if (log instanceof ProcessStateLog) {
2366: logger.debug("log:" + log);
2367: }
2368: }
2369: }
2370:
2371: /**
2372: * Gets process definition by name and version
2373: *
2374: * @param i_context
2375: * @param i_name
2376: * @param i_version
2377: * @return
2378: */
2379: private ProcessDefinition getProcessDef(JbpmContext i_context,
2380: String i_name, int i_version) {
2381:
2382: ProcessDefinition processDef = null;
2383:
2384: if (i_version == WORKFLOW_LAST_VERSION) {
2385: processDef = i_context.getGraphSession()
2386: .findLatestProcessDefinition(i_name);
2387: } else {
2388: processDef = i_context.getGraphSession()
2389: .findProcessDefinition(i_name, i_version);
2390: }
2391:
2392: return processDef;
2393: }
2394:
2395: /**
2396: * Returns Process Definition by id
2397: *
2398: * @param i_context
2399: * @param processDefId
2400: * @return
2401: */
2402: private ProcessDefinition getProcessDef(JbpmContext i_context,
2403: long processDefId) {
2404:
2405: ProcessDefinition processDef = null;
2406:
2407: processDef = i_context.getGraphSession().getProcessDefinition(
2408: processDefId);
2409:
2410: return processDef;
2411: }
2412:
2413: /**
2414: * Gets email of owner of task Owner may be user or role
2415: *
2416: * @param i_task
2417: * @return
2418: */
2419: private String getTaskOwnerEmail(TaskInstance i_task) {
2420:
2421: EmForgeUserDetails toUser = null;
2422:
2423: try {
2424: toUser = userFactory.getUser(i_task.getActorId());
2425: } catch (Exception ex) {
2426: // just ignore it here
2427: }
2428:
2429: if (toUser != null) {
2430: return toUser.getEmail();
2431: } else {
2432: // probably it is a group?
2433: ProjectDO project = ProcessTransformer.getProject(i_task
2434: .getToken().getProcessInstance());
2435: ProjectRole projectRole = userDao
2436: .getEmailByRoleNameAndProjectId(
2437: i_task.getActorId(), project.getId());
2438:
2439: if (projectRole != null) {
2440: return projectRole.getEmail();
2441: } else {
2442: return null;
2443: }
2444: }
2445: }
2446:
2447: /**
2448: * Set Variable into process instance
2449: *
2450: * @param processInstance
2451: * @param label
2452: * @param value
2453: */
2454: static private void setVariable(ProcessInstance processInstance,
2455: String label, Object value) {
2456:
2457: ContextInstance context = processInstance.getContextInstance();
2458: context.setVariable(label, value);
2459: }
2460:
2461: /**
2462: * @param processInstance
2463: * @param dueDate
2464: */
2465: public static void setDueDate(ProcessInstance processInstance,
2466: Date dueDate) {
2467:
2468: setVariable(processInstance, BpmVariable.DUEDATE.getVariable(),
2469: dueDate);
2470: }
2471:
2472: /**
2473: * @param processInstance
2474: * @param project
2475: */
2476: public static void setProject(ProcessInstance processInstance,
2477: ProjectDO project) {
2478:
2479: setVariable(processInstance, BpmVariable.PROJECT.getVariable(),
2480: project);
2481: }
2482:
2483: /**
2484: * Set Priority into Process Instance
2485: *
2486: * @param i_priority
2487: */
2488: public static void setPriority(ProcessInstance processInstance,
2489: Integer i_priority) {
2490:
2491: ContextInstance context = processInstance.getContextInstance();
2492: assert context != null;
2493:
2494: // get current priority
2495: Integer currentPrio = null;
2496: if (context.hasVariable(BpmVariable.PRIORITY.getVariable())
2497: && context.getVariable(BpmVariable.PRIORITY
2498: .getVariable()) != null) {
2499: Integer priority = Integer.valueOf(context.getVariable(
2500: BpmVariable.PRIORITY.getVariable()).toString());
2501: assert priority != null;
2502:
2503: currentPrio = priority;
2504: }
2505:
2506: // if currentPrio is not same as new prio
2507: if (currentPrio == null || !currentPrio.equals(i_priority)) {
2508: // set new value to the variable
2509: context.setVariable(BpmVariable.PRIORITY.getVariable(),
2510: i_priority);
2511:
2512: // propagate this priority to the all active tasks
2513: Collection<TaskInstance> unfinishedTasks = getBlockingTasks(processInstance);
2514: assert unfinishedTasks != null;
2515:
2516: for (TaskInstance task : unfinishedTasks) {
2517: task.setPriority(i_priority);
2518: }
2519:
2520: // and subprocesses
2521: List<ProcessInstance> blockingProcesses = new LinkedList<ProcessInstance>();
2522: Token rootToken = processInstance.getRootToken();
2523: getBlockingSubProcessesFromToken(rootToken,
2524: blockingProcesses);
2525:
2526: for (ProcessInstance subProcess : blockingProcesses) {
2527: setPriority(subProcess, i_priority);
2528: }
2529: }
2530: }
2531:
2532: /**
2533: * @param i_context
2534: * @param i_startStep
2535: * @param i_transitionName
2536: * @param i_tempPageName
2537: * @return
2538: */
2539: private Object startTaskImpl(JbpmContext i_context,
2540: StepTO i_startStep, String i_transitionName,
2541: String i_tempPageName) {
2542:
2543: // get workflow
2544: ProcessDefinition processDef = null;
2545: if (i_startStep.getWorkflowVersion() == null
2546: || i_startStep.getWorkflowVersion().equals(
2547: WORKFLOW_LAST_VERSION)) {
2548: processDef = i_context.getGraphSession()
2549: .findLatestProcessDefinition(
2550: i_startStep.getWorkflowName());
2551: } else {
2552: processDef = i_context.getGraphSession()
2553: .findProcessDefinition(
2554: i_startStep.getWorkflowName(),
2555: i_startStep.getWorkflowVersion());
2556: }
2557:
2558: if (processDef == null) {
2559: return new EmForgeException(
2560: "Cannot find specified workflow");
2561: }
2562:
2563: // create new process instance
2564: ProcessInstance proc = new ProcessInstance(processDef);
2565: assert proc != null;
2566:
2567: // get project
2568: ProjectDO project = projectService.getProject(i_startStep
2569: .getProjectName());
2570:
2571: // create a new taskinstance for the start task
2572: TaskInstance task = proc.getTaskMgmtInstance()
2573: .createStartTaskInstance();
2574: assert task != null;
2575:
2576: // check variables
2577: String message = checkVariables(i_startStep, task.getTask(),
2578: project.getName());
2579: if (message != null) {
2580: return new EmForgeException(message);
2581: }
2582:
2583: // set owner
2584: task.setVariable(BpmVariable.OWNER.getVariable(), userFactory
2585: .getCurrentUser().getUsername());
2586: // set project
2587: task.setVariable(BpmVariable.PROJECT.getVariable(), project);
2588:
2589: // initialize other default fields
2590: task.setVariable(BpmVariable.TITLE.getVariable(), i_startStep
2591: .getTitle());
2592: task.setPriority(i_startStep.getPriority().getValue());
2593: setPriority(proc, i_startStep.getPriority().getValue());
2594: task.setVariable(BpmVariable.DUEDATE.getVariable(), i_startStep
2595: .getDueDate());
2596:
2597: // now, fill this task instance with all passed variables
2598: for (VariableTO var : i_startStep.getWritableVariables()) {
2599: if (!BpmVariable.MILESTONE.getVariable().equals(
2600: var.getLabel())) {
2601: task.setVariable(var.getLabel(), var.getValue());
2602: } else {
2603: // special processing for milestone
2604: // @todo It is better to avoid such convertion and store milestone and project references as names, not
2605: // as ID
2606: MilestoneDO milestone = projectService.getMilestone(var
2607: .getValue());
2608: task.setVariable(var.getLabel(), milestone);
2609: }
2610:
2611: }
2612:
2613: // save start variable
2614: i_context.save(task);
2615:
2616: // now, we need complete start task with specified transition
2617: closeTask(i_context, task, i_transitionName);
2618:
2619: // if temporary wiki page was specified - we should rename it into process id
2620: // so, it's contents will be available as task description
2621: if (!StringUtils.isEmpty(i_tempPageName)) {
2622: WikiPage newpage = new WikiPage(getWikiEngine(),
2623: i_tempPageName);
2624: WikiContext wikiContext = new WikiContext(getWikiEngine(),
2625: newpage);
2626:
2627: try {
2628: getWikiEngine().renamePage(wikiContext, i_tempPageName,
2629: String.valueOf(proc.getId()), false);
2630: } catch (WikiException wikiException) {
2631: logger.error("Cannot rename teporary page "
2632: + i_tempPageName + " into task page "
2633: + String.valueOf(proc.getId()), wikiException);
2634: }
2635: }
2636:
2637: // now, we need to convert our process instance into task TO and return it
2638: // first of all - flush session and refresh object
2639: i_context.getSession().flush();
2640: i_context.getSession().refresh(proc);
2641:
2642: return proc;
2643: }
2644:
2645: /**
2646: * Is current user owner of specified task?
2647: *
2648: * @param i_task
2649: * @return
2650: */
2651: private boolean isTaskOwner(TaskTO i_task) {
2652:
2653: return userFactory.getCurrentUser().getUsername().equals(
2654: i_task.getOwner());
2655: }
2656:
2657: /**
2658: * Is current user project manager for project, related to specified task?
2659: *
2660: * @param i_task
2661: * @return
2662: */
2663: private boolean isProjectManager(String projectName) {
2664:
2665: ProjectDO project = projectService.getProject(projectName);
2666: if (project != null) {
2667: return projectService.hasRole(project, userFactory
2668: .getCurrentUser(), ProjectService.ROLE_MANAGER);
2669:
2670: }
2671:
2672: return false;
2673:
2674: }
2675:
2676: /**
2677: * Is Current user - Site Admin?
2678: *
2679: * @return
2680: */
2681: private boolean isAdmin() {
2682:
2683: return userFactory.getCurrentUser().hasRole(
2684: SiteRole.ADMIN.getId());
2685: }
2686:
2687: /**
2688: * @param i_step
2689: * @return
2690: */
2691: private boolean isStepOwner(StepTO i_step) {
2692:
2693: return StringUtils.equals(userFactory.getCurrentUser()
2694: .getUsername(), i_step.getActor());
2695: }
2696:
2697: /**
2698: * @param i_step
2699: * @return
2700: */
2701: private boolean isGroupMember(StepTO i_step) {
2702:
2703: ProjectDO project = projectService.getProject(i_step
2704: .getProjectName());
2705: if (project == null) {
2706: return false;
2707: }
2708:
2709: // Is task owner - role name?
2710: Role role = getAssignedRole(i_step);
2711: if (role == null) {
2712: return false;
2713: }
2714:
2715: return projectService.hasRole(project, userFactory
2716: .getCurrentUser(), role);
2717: }
2718:
2719: /**
2720: * @param i_step
2721: * @return
2722: */
2723: private Role getAssignedRole(StepTO i_step) {
2724:
2725: // Is task owner - role name?
2726: Role role = userFactory.getRole(i_step.getActor());
2727: return role;
2728: }
2729:
2730: /**
2731: * @param i_context
2732: * @param i_is
2733: * @param i_comment
2734: * @return
2735: * @throws IOException
2736: */
2737: private ProcessDefinition deployProcessDef(JbpmContext i_context,
2738: InputStream i_is, String i_comment) throws IOException {
2739:
2740: ZipInputStream zis = new ZipInputStream(i_is);
2741: ProcessDefinition processDefinition = ProcessDefinition
2742: .parseParZipInputStream(zis);
2743:
2744: // add special events
2745: logger.info("Adding special events handlers: "
2746: + processDefinition.getName());
2747:
2748: // add event for processing task-create action
2749: Action taskCreateAction = new Action();
2750: taskCreateAction.setActionDelegation(EmForgeJpdlReader
2751: .createSpringDelegation("taskCreatedEvent"));
2752:
2753: Event taskCreateEvent = new Event(Event.EVENTTYPE_TASK_CREATE);
2754: taskCreateEvent.addAction(taskCreateAction);
2755:
2756: processDefinition.addEvent(taskCreateEvent);
2757: // -----
2758:
2759: // add event for processing task-assign action
2760: Action taskAssignAction = new Action();
2761: taskAssignAction.setActionDelegation(EmForgeJpdlReader
2762: .createSpringDelegation("taskAssignEvent"));
2763:
2764: Event taskAssignEvent = new Event(Event.EVENTTYPE_TASK_ASSIGN);
2765: taskAssignEvent.addAction(taskAssignAction);
2766:
2767: processDefinition.addEvent(taskAssignEvent);
2768: // -----
2769:
2770: // add event for creation subprocess and propagation process data from superprocess to subprocess
2771: Action subProcessCreateAction = new Action();
2772: subProcessCreateAction.setActionDelegation(EmForgeJpdlReader
2773: .createSpringDelegation("subprocessCreatedEvent"));
2774:
2775: Event subProcessCreateEvent = new Event(
2776: Event.EVENTTYPE_SUBPROCESS_CREATED);
2777: subProcessCreateEvent.addAction(subProcessCreateAction);
2778:
2779: processDefinition.addEvent(subProcessCreateEvent);
2780: // -----
2781:
2782: String userName = "";
2783: if (userFactory.getCurrentUser() != null) {
2784: userName = userFactory.getCurrentUser().getUsername();
2785: }
2786:
2787: // create comment by adding date and user information
2788: String fullComment = DATE_SEPARATOR + (new Date()).getTime()
2789: + USER_SEPARATOR + userName + MESSAGE_SEPARATOR
2790: + i_comment;
2791: processDefinition.getFileDefinition().addFile(COMMENT_FILENAME,
2792: fullComment.getBytes());
2793:
2794: logger
2795: .info("Deploying process: "
2796: + processDefinition.getName());
2797:
2798: i_context.deployProcessDefinition(processDefinition);
2799: zis.close();
2800:
2801: // to be able to find new process definition in the same
2802: // http-request we should make flush here
2803: i_context.getSession().flush();
2804:
2805: logger.info("Deployed process " + processDefinition.getName()
2806: + " successfully");
2807:
2808: return processDefinition;
2809: }
2810:
2811: /**
2812: * Very specific method This code got from jBPM and used for image generation It should be used onli inside
2813: * ProcessImageComponent
2814: *
2815: * @param writer
2816: * @param i_workflow
2817: * @param i_task
2818: * @param i_step
2819: * @throws DocumentException
2820: * @throws IOException
2821: * @todo REFACTOR IT! it is currently ugly
2822: */
2823: public String writeWorkflowImageTable(final WorkflowTO i_workflow,
2824: final TaskTO i_task, final StepTO i_step)
2825: throws EmForgeException {
2826:
2827: Writer writer = new StringWriter();
2828:
2829: try {
2830: String currentTokenColor = "red";
2831: String childTokenColor = "blue";
2832: String tokenNameColor = "blue";
2833:
2834: byte[] gpdBytes = retrieveByteArrays(i_workflow, i_task,
2835: i_step);
2836:
2837: if (gpdBytes == null) {
2838: return null;
2839: }
2840:
2841: int borderWidth = 4;
2842: Element rootDiagramElement = DocumentHelper.parseText(
2843: new String(gpdBytes)).getRootElement();
2844: int[] boxConstraint;
2845: int[] imageDimension = extractImageDimension(rootDiagramElement);
2846: String imageLink = Helper.getPath()
2847: + "/processimage?"
2848: + WorkflowController.WORKFLOW_ID_ATTR
2849: + "="
2850: + getWorkflowImpl(i_workflow, i_task, i_step)
2851: .getId();
2852:
2853: // Draw image for processInstance
2854: if (i_task != null) {
2855: ProcessInstance processInstance = (ProcessInstance) execute(new JbpmCallback() {
2856:
2857: public Object doInJbpm(JbpmContext context) {
2858:
2859: return context.getProcessInstance(i_task
2860: .getId());
2861: }
2862: });
2863: List<Token> allTokens = new LinkedList<Token>();
2864:
2865: walkTokens(processInstance.getRootToken(), allTokens);
2866:
2867: writer
2868: .write("<div style='position:relative; background-image:url("
2869: + imageLink
2870: + "); width: "
2871: + imageDimension[0]
2872: + "px; height: "
2873: + imageDimension[1] + "px;'>");
2874: writer.write("\n");
2875:
2876: for (int i = 0; i < allTokens.size(); i++) {
2877: Token token = allTokens.get(i);
2878:
2879: // check how many tokens are on teh same level (= having the same parent)
2880: int offset = i;
2881: if (i > 0) {
2882: while (offset > 0
2883: && ((Token) allTokens.get(offset - 1))
2884: .getParent().equals(
2885: token.getParent())) {
2886: offset--;
2887: }
2888: }
2889:
2890: boxConstraint = extractBoxConstraint(
2891: rootDiagramElement, token);
2892:
2893: // Adjust for borders
2894: boxConstraint[2] -= borderWidth * 2;
2895: boxConstraint[3] -= borderWidth * 2;
2896:
2897: writer
2898: .write("<div style='position:absolute; left: "
2899: + boxConstraint[0]
2900: + "px; top: "
2901: + boxConstraint[1] + "px; ");
2902: writer.write("\n");
2903:
2904: if (i == (allTokens.size() - 1)) {
2905: writer.write("border: " + currentTokenColor);
2906: writer.write("\n");
2907: } else {
2908: writer.write("border: " + childTokenColor);
2909: writer.write("\n");
2910: }
2911:
2912: writer.write(" " + borderWidth + "px groove; "
2913: + "width: " + boxConstraint[2]
2914: + "px; height: " + boxConstraint[3]
2915: + "px;'>");
2916: writer.write("\n");
2917:
2918: if (token.getName() != null) {
2919: writer
2920: .write("<span style='color:"
2921: + tokenNameColor
2922: + ";font-style:italic;position:absolute;left:"
2923: + (boxConstraint[2] + 10)
2924: + "px;top:"
2925: + ((i - offset) * 20)
2926: + ";'> " + token.getName()
2927: + "</span>");
2928: writer.write("\n");
2929: }
2930:
2931: writer.write("</div>");
2932: writer.write("\n");
2933: }
2934:
2935: writer.write("</div>");
2936: writer.write("\n");
2937: } else if (i_step != null) {
2938: TaskInstance taskInstance = (TaskInstance) execute(new JbpmCallback() {
2939:
2940: public Object doInJbpm(JbpmContext context) {
2941:
2942: return context.getTaskInstance(i_step.getId());
2943: }
2944: });
2945:
2946: boxConstraint = extractBoxConstraint(
2947: rootDiagramElement, taskInstance);
2948:
2949: writer
2950: .write("<table border=0 cellspacing=0 cellpadding=0 width="
2951: + imageDimension[0]
2952: + " height="
2953: + imageDimension[1] + ">");
2954: writer.write("\n");
2955: writer.write(" <tr>");
2956: writer.write("\n");
2957: writer.write(" <td width=" + imageDimension[0]
2958: + "px height=" + imageDimension[1]
2959: + "px style=\"background-image:url("
2960: + imageLink + ")\" valign=top>");
2961: writer.write("\n");
2962: writer
2963: .write(" <table border=0 cellspacing=0 cellpadding=0 style=\"border-width:0px; background-color:transparent;\">");
2964: writer.write("\n");
2965: writer.write(" <tr>");
2966: writer.write("\n");
2967: writer
2968: .write(" <td width="
2969: + (boxConstraint[0] - borderWidth)
2970: + " height="
2971: + (boxConstraint[1] - borderWidth)
2972: + " style=\"background-color:transparent;\" border=0></td>");
2973: writer.write("\n");
2974: writer.write(" </tr>");
2975: writer.write("\n");
2976: writer.write(" <tr>");
2977: writer.write("\n");
2978: writer
2979: .write(" <td style=\"background-color:transparent;\" border=0></td>");
2980: writer.write("\n");
2981: writer
2982: .write(" <td style=\"border-color:"
2983: + currentTokenColor
2984: + "; border-width:"
2985: + borderWidth
2986: + "px; border-style:groove; background-color:transparent;\" width="
2987: + boxConstraint[2]
2988: + " height="
2989: + (boxConstraint[3] + (2 * borderWidth))
2990: + "> </td>");
2991: writer.write("\n");
2992: writer.write(" </tr>");
2993: writer.write("\n");
2994: writer.write(" </table>");
2995: writer.write("\n");
2996: writer.write(" </td>");
2997: writer.write("\n");
2998: writer.write(" </tr>");
2999: writer.write("\n");
3000: writer.write("</table>");
3001: writer.write("\n");
3002: } else if (i_task == null && i_workflow != null) {
3003: // / @todo maybe change to image tag
3004: writer
3005: .write("<div style='position:relative; background-image:url("
3006: + imageLink
3007: + "); width: "
3008: + imageDimension[0]
3009: + "px; height: "
3010: + imageDimension[1] + "px;'></div>");
3011: writer.write("\n");
3012: }
3013:
3014: return writer.toString();
3015: } catch (Exception ex) {
3016: throw new EmForgeException(
3017: "Cannot generate workflow image", ex);
3018: }
3019: }
3020:
3021: /**
3022: * @param i_workflow
3023: * @param i_task
3024: * @param i_step
3025: * @return
3026: */
3027: private byte[] retrieveByteArrays(WorkflowTO i_workflow,
3028: TaskTO i_task, StepTO i_step) {
3029:
3030: try {
3031: ProcessDefinition processDef = getWorkflowImpl(i_workflow,
3032: i_task, i_step);
3033: FileDefinition fileDefinition = processDef
3034: .getFileDefinition();
3035: return fileDefinition.getBytes("gpd.xml");
3036: } catch (Exception e) {
3037: logger.error("Cannot get process def gdp.xml", e);
3038: return null;
3039: }
3040: }
3041:
3042: /**
3043: * @param i_workflow
3044: * @param i_task
3045: * @param i_step
3046: * @return
3047: */
3048: private ProcessDefinition getWorkflowImpl(
3049: final WorkflowTO i_workflow, final TaskTO i_task,
3050: final StepTO i_step) {
3051:
3052: ProcessDefinition processDef = (ProcessDefinition) execute(new JbpmCallback() {
3053:
3054: public Object doInJbpm(JbpmContext context) {
3055:
3056: if (i_workflow != null) {
3057: return context.getGraphSession()
3058: .getProcessDefinition(i_workflow.getId());
3059: }
3060:
3061: if (i_task != null) {
3062: return getProcessDef(context, i_task
3063: .getWorkflowName(), i_task
3064: .getWorkflowVersion());
3065: }
3066:
3067: if (i_step != null) {
3068: return getProcessDef(context, i_step
3069: .getWorkflowName(), i_step
3070: .getWorkflowVersion());
3071: }
3072:
3073: return null;
3074: }
3075: });
3076:
3077: return processDef;
3078: }
3079:
3080: /**
3081: * @param root
3082: * @param i_taskInstance
3083: * @return
3084: */
3085: private int[] extractBoxConstraint(Element root,
3086: TaskInstance i_taskInstance) {
3087:
3088: int[] result = new int[4];
3089: try {
3090: String nodeName = i_taskInstance.getToken().getNode()
3091: .getName();
3092: XPath xPath = new DefaultXPath("//node[@name='" + nodeName
3093: + "']");
3094: Element node = (Element) xPath.selectSingleNode(root);
3095: result[0] = Integer.valueOf(node.attribute("x").getValue())
3096: .intValue();
3097: result[1] = Integer.valueOf(node.attribute("y").getValue())
3098: .intValue();
3099: result[2] = Integer.valueOf(
3100: node.attribute("width").getValue()).intValue();
3101:
3102: // [AKA] Fixed (probably incorrectly problem with -1 in the width
3103: if (result[2] == -1) {
3104: result[2] = 150;
3105: }
3106:
3107: result[3] = Integer.valueOf(
3108: node.attribute("height").getValue()).intValue();
3109: } catch (Exception ex) {
3110: // due to some problems with incorrect process definition we can get errors here
3111: // but still - we should be able to display image
3112: logger.error("Cannot get box contraints", ex);
3113: result[0] = 0;
3114: result[1] = 0;
3115: result[2] = 0;
3116: result[3] = 0;
3117: }
3118: return result;
3119: }
3120:
3121: /**
3122: * @param root
3123: * @param token
3124: * @return
3125: */
3126: private int[] extractBoxConstraint(Element root, Token token) {
3127:
3128: int[] result = new int[4];
3129: try {
3130: String nodeName = token.getNode().getName();
3131: XPath xPath = new DefaultXPath("//node[@name=" + '"'
3132: + nodeName + '"' + "]");
3133: Element node = (Element) xPath.selectSingleNode(root);
3134: result[0] = Integer.valueOf(node.attribute("x").getValue())
3135: .intValue();
3136: result[1] = Integer.valueOf(node.attribute("y").getValue())
3137: .intValue();
3138: result[2] = Integer.valueOf(
3139: node.attribute("width").getValue()).intValue();
3140: result[3] = Integer.valueOf(
3141: node.attribute("height").getValue()).intValue();
3142: } catch (Exception ex) {
3143: // due to some problems with incorrect process definition we can get errors here
3144: // but still - we should be able to display image
3145: logger.error("Cannot get box contraints", ex);
3146: result[0] = 0;
3147: result[1] = 0;
3148: result[2] = 0;
3149: result[3] = 0;
3150: }
3151: return result;
3152: }
3153:
3154: /**
3155: * @param root
3156: * @return
3157: */
3158: private int[] extractImageDimension(Element root) {
3159:
3160: int[] result = new int[2];
3161: result[0] = Integer.valueOf(root.attribute("width").getValue())
3162: .intValue();
3163: result[1] = Integer
3164: .valueOf(root.attribute("height").getValue())
3165: .intValue();
3166: return result;
3167: }
3168:
3169: /**
3170: * @param i_parent
3171: * @param o_allTokens
3172: */
3173: @SuppressWarnings("unchecked")
3174: private void walkTokens(Token i_parent,
3175: Collection<Token> o_allTokens) {
3176:
3177: Map<Object, Token> children = i_parent.getChildren();
3178: if (children != null && children.size() > 0) {
3179: for (Token child : children.values()) {
3180: walkTokens(child, o_allTokens);
3181: }
3182: }
3183:
3184: o_allTokens.add(i_parent);
3185: }
3186:
3187: /**
3188: * Method used in Process Icon Servlet
3189: *
3190: * @param workflowId
3191: * @return
3192: */
3193: public byte[] getWorkflowIcon(final long workflowId) {
3194:
3195: byte[] icon = (byte[]) execute(new JbpmCallback() {
3196:
3197: public Object doInJbpm(JbpmContext context) {
3198:
3199: ProcessDefinition processDef = getProcessDef(context,
3200: workflowId);
3201:
3202: if (processDef == null) {
3203: return null;
3204: }
3205:
3206: return ProcessDefTransformer
3207: .getWorkflowIcon(processDef);
3208: }
3209: });
3210:
3211: return icon;
3212:
3213: }
3214:
3215: /**
3216: * Returns workflow image
3217: *
3218: * @param workflowId
3219: * @return
3220: */
3221: public byte[] getWorkflowImage(final long workflowId) {
3222:
3223: byte[] icon = (byte[]) execute(new JbpmCallback() {
3224:
3225: public Object doInJbpm(JbpmContext context) {
3226:
3227: ProcessDefinition processDef = getProcessDef(context,
3228: workflowId);
3229:
3230: if (processDef == null) {
3231: return null;
3232: }
3233:
3234: return ProcessDefTransformer
3235: .getWorkflowImage(processDef);
3236: }
3237: });
3238:
3239: return icon;
3240:
3241: }
3242: }
|