001: package org.emforge.jbpm.web.bean;
002:
003: import java.util.Collection;
004: import java.util.LinkedList;
005:
006: import org.apache.commons.lang.StringUtils;
007: import org.apache.commons.logging.Log;
008: import org.apache.commons.logging.LogFactory;
009: import org.emforge.BpmService;
010: import org.emforge.CommentService;
011: import org.emforge.EmForgeException;
012: import org.emforge.projectmanager.ProjectService;
013: import org.emforge.projectmanager.base.MilestoneDO;
014: import org.emforge.projectmanager.base.ProjectDO;
015: import org.emforge.xfer.AttachmentTO;
016: import org.emforge.xfer.CommentTO;
017: import org.emforge.xfer.HistoryTO;
018: import org.emforge.xfer.StepTO;
019: import org.emforge.xfer.TaskTO;
020: import org.emforge.xfer.VariableTO;
021: import org.emforge.xfer.WorkflowTO;
022:
023: import ru.emdev.EmForge.security.UserFactory;
024: import ru.emdev.EmForge.web.bean.BaseControllerImpl;
025: import ru.emdev.EmForge.web.bean.EditTextController;
026: import ru.emdev.EmForge.web.bean.MainMenuController.MainMenuItem;
027: import ru.emdev.EmForge.wiki.web.bean.BaseWikiControllerImpl;
028: import ru.emdev.EmForge.wiki.web.bean.Crumb;
029:
030: /** Controller for processing task form
031: *
032: * @todo Currently, on interface level we are already using task - but for now controller processed
033: * process. It should be fixed as soon as renaming will be done
034: *
035: */
036: public class TaskController extends BaseControllerImpl {
037: protected final Log logger = LogFactory.getLog(getClass());
038:
039: public static final String TASK_PAGE_NAME = "task";
040: public static final String TASK_ID_ATTR = "taskid";
041: public static final String STEP_NUM_ATTR = "stepnum";
042: public static final String STEP_ID_ATTR = "stepid";
043:
044: private TaskTO task;
045: private Collection<VariableTO> writableVariables;
046:
047: private Collection<StepBean> userBlockingSteps;
048: private Collection<StepBean> otherBlockingSteps;
049:
050: private StepBean processedStepBean;
051: private StepTO processedStep;
052:
053: private BpmService bpmService;
054: private CommentService commentService;
055: private ProjectService projectService;
056: private UserFactory userFactory;
057: private EditTextController editTextController;
058: private NewTaskController newTaskController;
059:
060: // setters
061: public void setBpmService(BpmService i_bpmService) {
062: this .bpmService = i_bpmService;
063: }
064:
065: public void setCommentService(CommentService i_commentService) {
066: commentService = i_commentService;
067: }
068:
069: public void setEditTextController(
070: EditTextController i_editTextController) {
071: editTextController = i_editTextController;
072: }
073:
074: public void setProjectService(ProjectService i_projectService) {
075: projectService = i_projectService;
076: }
077:
078: public void setUserFactory(UserFactory i_userFactory) {
079: userFactory = i_userFactory;
080: }
081:
082: public void setNewTaskController(
083: NewTaskController i_newTaskController) {
084: newTaskController = i_newTaskController;
085: }
086:
087: // common methods
088: @Override
089: public MainMenuItem getSelectionItemOnMainMenu() {
090: return MainMenuItem.TASKS;
091: }
092:
093: @Override
094: public String getTitleImpl() {
095: if (task == null) {
096: return null;
097: } else {
098: return "Task #" + getTaskId() + " : " + task.getTitle();
099: }
100: }
101:
102: @Override
103: public Crumb getTrailCrumbInfo() {
104: if (task == null) {
105: return null;
106: }
107: String displayName;
108: String url;
109: try {
110: String taskId = Long.toString(task.getId());
111: displayName = "Task #" + taskId;
112: url = TASK_PAGE_NAME + "/" + taskId;
113: } catch (Exception ex) {
114: logger.debug("Cannot get trail crumb info: ", ex);
115: return null;
116: }
117:
118: return new Crumb(displayName, url);
119: }
120:
121: @Override
122: protected void init() {
123: Long id = getId(TASK_ID_ATTR);
124:
125: if (id == null) {
126: // some controls (like attachment list) passed id of task in page param
127: id = getId(BaseWikiControllerImpl.PAGE_PARAM_NAME);
128: }
129:
130: if (id != null) {
131: setTaskId(id);
132: }
133:
134: Long num = getId(STEP_NUM_ATTR);
135: if (num != null) {
136: try {
137: setProcessedStepNum(new Integer(num.intValue()));
138: } catch (EmForgeException ex) {
139: logger.error("Cannot set processed step", ex);
140: }
141: } else {
142: Long stepId = getId(STEP_ID_ATTR);
143:
144: if (stepId != null) {
145: try {
146: setProcessedStepId(stepId);
147: } catch (EmForgeException ex) {
148: logger.error("Cannot set processed step", ex);
149: }
150: }
151: }
152: }
153:
154: public Long getTaskId() {
155: if (task != null) {
156: return task.getId();
157: } else {
158: return null;
159: }
160: }
161:
162: public void setTaskId(Long newTaskId) {
163: try {
164: if (newTaskId == null) {
165: task = null;
166: } else {
167: task = bpmService.getTask(newTaskId);
168: }
169:
170: writableVariables = null;
171: userBlockingSteps = null;
172: otherBlockingSteps = null;
173: processedStepBean = null;
174: processedStep = null;
175: } catch (EmForgeException ex) {
176: logger.error("Cannot get task #" + newTaskId, ex);
177: }
178: }
179:
180: public TaskTO getTask() {
181: return task;
182: }
183:
184: public Integer getProcessedStepNum() {
185: if (processedStepBean == null) {
186: return null;
187: } else {
188: return processedStepBean.getNum();
189: }
190: }
191:
192: public void setProcessedStepNum(Integer i_processedStepNum)
193: throws EmForgeException {
194: if (i_processedStepNum == null) {
195: processedStepBean = null;
196: } else {
197: // find it in user blocking steps
198: for (StepBean step : getUserBlockingSteps()) {
199: if (step.getNum().equals(i_processedStepNum)) {
200: processedStepBean = step;
201: }
202: }
203: }
204:
205: }
206:
207: public Long getProcessedStepId() {
208: if (processedStepBean != null) {
209: return processedStepBean.getId();
210: } else if (processedStep != null) {
211: return processedStep.getId();
212: } else {
213: return null;
214: }
215: }
216:
217: public void setProcessedStepId(Long stepId) throws EmForgeException {
218: if (stepId == null) {
219: processedStepBean = null;
220: processedStep = null;
221: } else {
222: // find it in user blocking steps
223: for (StepBean step : getUserBlockingSteps()) {
224: if (step.getId().equals(stepId)) {
225: processedStepBean = step;
226: }
227: }
228:
229: if (processedStepBean == null) {
230: processedStep = bpmService.getStep(stepId);
231: }
232: }
233:
234: }
235:
236: public TaskTO getParentTask() throws EmForgeException {
237: if (task == null || task.getParentTaskId() == null) {
238: return null;
239: } else {
240: return bpmService.getTask(task.getParentTaskId());
241: }
242: }
243:
244: /** Returns String with task status,
245: * depending from is task finished or not, how much steps it has, that the steps it corrently sta
246: */
247: public String getTaskStatus() throws EmForgeException {
248: if (task == null) {
249: return null;
250: }
251:
252: if (task.getHasEnded()) {
253: return "Task is closed";
254: } else {
255: StepTO[] blockingSteps = bpmService.getBlockingSteps(task
256: .getId());
257: String prefix = "Task at step ";
258: if (blockingSteps.length > 1) {
259: prefix = "Task at steps: ";
260: }
261:
262: String stepNames = "";
263:
264: for (StepTO step : blockingSteps) {
265: if (!StringUtils.isEmpty(stepNames)) {
266: stepNames += ", ";
267: }
268:
269: stepNames += step.getName();
270: }
271:
272: return prefix + stepNames;
273: }
274: }
275:
276: public WorkflowTO getWorkflow() throws EmForgeException {
277: if (task == null) {
278: return null;
279: } else {
280: return bpmService.getWorkflowByName(task.getWorkflowName(),
281: task.getWorkflowVersion());
282: }
283: }
284:
285: public ProjectDO getTaskProject() {
286: if (task == null) {
287: return null;
288: }
289:
290: if (task.getProjectName() == null) {
291: return null;
292: }
293:
294: return projectService.getProject(task.getProjectName());
295: }
296:
297: public MilestoneDO getTaskMilestone() {
298: if (task == null) {
299: return null;
300: }
301:
302: if (task.getMilestoneName() == null) {
303: return null;
304: }
305:
306: return projectService.getMilestone(task.getMilestoneName());
307: }
308:
309: // working with comments
310: public CommentTO[] getComments() {
311: try {
312: if (task != null) {
313: return commentService.getComments(String.valueOf(task
314: .getId()));
315: }
316: } catch (Exception ex) {
317: addErrorMessage("Cannot read comments", ex.getMessage());
318: }
319:
320: return null;
321: }
322:
323: public String getComment() {
324: return editTextController.getWikiText();
325: }
326:
327: public void clearComment() {
328: editTextController.setWikiText(null);
329: }
330:
331: public String addComment() {
332: try {
333: String newComment = editTextController.getWikiText();
334:
335: if (StringUtils.isNotEmpty(newComment)) {
336: bpmService.addComment(task.getId(), newComment);
337: editTextController.setWikiText(null);
338: }
339: } catch (Exception ex) {
340: addErrorMessage("Cannot save attachment", ex.toString());
341: }
342:
343: return null;
344: }
345:
346: // Working with attachments
347: @SuppressWarnings("unchecked")
348: public AttachmentTO[] getAttachments() {
349: if (task != null) {
350: try {
351: return m_attachmentService.getAttachments(task.getId()
352: .toString());
353: } catch (EmForgeException ex) {
354: logger.error("Cannot get list of attachments", ex);
355: }
356: }
357:
358: return new AttachmentTO[0];
359: }
360:
361: // working with blocking steps
362: public Collection<StepBean> getUserBlockingSteps()
363: throws EmForgeException {
364: if (userBlockingSteps == null) {
365: readBlockingSteps();
366: }
367:
368: return userBlockingSteps;
369: }
370:
371: private void readBlockingSteps() throws EmForgeException {
372: if (task == null) {
373: return;
374: }
375:
376: userBlockingSteps = new LinkedList<StepBean>();
377: otherBlockingSteps = new LinkedList<StepBean>();
378:
379: int i = 1;
380: for (StepTO step : bpmService.getBlockingSteps(task.getId())) {
381: StepBean stepBean = new StepBean(this , i++, projectService,
382: userFactory, bpmService, newTaskController, step);
383:
384: if (stepBean.isCanSubmit()) {
385: userBlockingSteps.add(stepBean);
386: } else {
387: otherBlockingSteps.add(stepBean);
388: }
389: }
390: }
391:
392: // working with variables
393: public VariableTO[] getTaskVariables() {
394: if (task != null) {
395: return task.getVariables();
396: } else {
397: return new VariableTO[0];
398: }
399: }
400:
401: public Collection<VariableTO> getWritableTaskVariables()
402: throws EmForgeException {
403: if (writableVariables == null) {
404: readVariables();
405: }
406:
407: return writableVariables;
408: }
409:
410: @SuppressWarnings("unchecked")
411: private void readVariables() throws EmForgeException {
412: if (task != null) {
413: writableVariables = new LinkedList<VariableTO>();
414:
415: for (VariableTO var : task.getVariables()) {
416: // admin and project manager allowed to edit any variables
417: if (isProjectManager() || isAdmin()) {
418: writableVariables.add(var);
419: } else if (isTaskOwner()) {
420: // task owner allowed to edit only variables, he specified then started task
421: // so, we need to get list of varialbes in start task
422: StepTO startStep = bpmService.getWorkflowStartStep(
423: task.getWorkflowName(), task
424: .getWorkflowVersion(), task
425: .getProjectName());
426:
427: for (VariableTO startVar : startStep
428: .getWritableVariables()) {
429: if (startVar.getLabel().equals(var.getLabel())) {
430: // add it into writable variables
431: writableVariables.add(var);
432: }
433: }
434: }
435: }
436: }
437: }
438:
439: public String stopTask() {
440: if (!isCanStopTask()) {
441: addErrorMessage("You are not allowed to stop this task",
442: "You are not allowed to stop this task");
443: return null;
444: }
445:
446: try {
447: bpmService.stopTask(task.getId(), getComment());
448: } catch (EmForgeException ex) {
449: addErrorMessage("Cannot stop task", ex.getMessage());
450: }
451:
452: // refresh controller to remove all collections of blocking tasks and so on
453: setTaskId(getTaskId());
454: return null;
455: }
456:
457: public String saveTaskSettings() {
458: if (!isCanSaveTaskSettings()) {
459: addErrorMessage(
460: "You are not allowed to change settings of this task",
461: "You are not allowed to change settings of this task");
462: return null;
463: }
464:
465: // save task
466: try {
467: bpmService.saveTask(task, getComment());
468: } catch (EmForgeException ex) {
469: addErrorMessage("Cannot save task changes", ex.getMessage());
470: }
471:
472: return null;
473: }
474:
475: /** Display Other Blocking Steps tab only if there will be something displayed
476: *
477: * @return
478: */
479: public boolean isDisplayOtherBlockingSteps()
480: throws EmForgeException {
481: TaskTO[] blockingSubTasks = bpmService.getBlockingSubTasks(task
482: .getId());
483: return getOtherBlockingSteps().size() > 0
484: || blockingSubTasks.length > 0;
485: }
486:
487: public TaskTO[] getBlockingSubTasks() throws EmForgeException {
488: if (task == null) {
489: return new TaskTO[0];
490: }
491:
492: return bpmService.getBlockingSubTasks(task.getId());
493: }
494:
495: /** Use title for "Other Blocking Steps" depending from
496: * has user some own steps in this task or not
497: */
498: public String getOtherBlockingStepsTitle() throws EmForgeException {
499: if (getUserBlockingSteps().size() > 0) {
500: return "Other Blockers";
501: } else {
502: return "Blockers";
503: }
504: }
505:
506: /** Returns list of blocking steps, not displayed on separate tabs.
507: *
508: * That means - steps, there user has not rights to edit something.
509: * @return
510: */
511: public Collection<StepBean> getOtherBlockingSteps()
512: throws EmForgeException {
513: if (otherBlockingSteps == null) {
514: readBlockingSteps();
515: }
516:
517: return otherBlockingSteps;
518: }
519:
520: /** Display Task Settings Tab only if user allowed to change or stop the task
521: *
522: * @return
523: */
524: public boolean isDisplayTaskSettings() {
525: return isCanSaveTaskSettings() || isCanStopTask();
526: }
527:
528: public HistoryTO[] getTaskHistory() throws EmForgeException {
529: if (task == null) {
530: return new HistoryTO[0];
531: }
532:
533: return bpmService.getTaskHistory(task.getId());
534: }
535:
536: public StepBean getProcessedStep() {
537: return processedStepBean;
538: }
539:
540: // Security checks
541: protected boolean isTaskOwner() {
542: return task != null
543: && m_appContext.getUserService().getCurrentUser()
544: .getUsername().equals(task.getOwner());
545: }
546:
547: protected boolean isProjectManager() {
548: ProjectDO project = getTaskProject();
549:
550: if (project != null) {
551: return projectService.hasRole(project, getCurrentUser(),
552: ProjectService.ROLE_MANAGER);
553:
554: }
555:
556: return false;
557: }
558:
559: /** Is current user allowed to add attachments?
560: */
561: public boolean isCanAddAttachment() {
562: return bpmService.canAddAttachment(task.getId());
563: }
564:
565: public boolean isCanAddComment() {
566: return bpmService.canCommentTask(task.getId());
567: }
568:
569: public boolean isCanEditDescription() {
570: return bpmService.canEditTaskDescription(task);
571: }
572:
573: public boolean isCanSaveTaskSettings() {
574: return bpmService.canChangeTask(task);
575: }
576:
577: public boolean isCanStopTask() {
578: return bpmService.canStopTask(task);
579: }
580:
581: public boolean isCanReassignSteps() {
582: return bpmService.canReassignSteps(task);
583: }
584:
585: /** Attributes and methods, related to request status implementation */
586: /** Additional message, included into status request */
587: String m_statusRequestMessage = "Could you inform me about status for the task";
588:
589: /** True - if request was already sent, otherwise false. Used for Ajax */
590: boolean m_requestSent = false;
591:
592: public void setStatusRequestMessage(String i_statusRequestMessage) {
593: m_statusRequestMessage = i_statusRequestMessage;
594: }
595:
596: public String getStatusRequestMessage() {
597: return m_statusRequestMessage;
598: }
599:
600: public boolean isRequestSent() {
601: return m_requestSent;
602: }
603:
604: public boolean isCanRequestStatus() throws EmForgeException {
605: StepBean step = (StepBean) getValue("#{blockingStep}");
606: if (step != null) {
607: return bpmService.isPossibleRequestStatus(step.getId());
608: } else {
609: return false;
610: }
611: }
612:
613: public String requestStatus() {
614: Long stepId = null;
615:
616: if (processedStepBean != null) {
617: stepId = processedStepBean.getId();
618: } else if (processedStep != null) {
619: stepId = processedStep.getId();
620: }
621:
622: if (stepId != null) {
623: try {
624: m_requestSent = bpmService.requestStatus(stepId,
625: m_statusRequestMessage);
626: } catch (EmForgeException ex) {
627: addErrorMessage("Cannot send request", ex.getMessage());
628: }
629: }
630:
631: return null;
632: }
633: }
|