001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: ProcessMgmt.java,v 1.39 2007/09/07 19:17:17 mlipp Exp $
021: *
022: * $Log: ProcessMgmt.java,v $
023: * Revision 1.39 2007/09/07 19:17:17 mlipp
024: * Added reload button.
025: *
026: * Revision 1.38 2007/09/05 21:49:51 mlipp
027: * Fixed problem with filters not showing effect immediately.
028: *
029: * Revision 1.37 2007/03/04 20:09:41 mlipp
030: * Optimized table model loading.
031: *
032: * Revision 1.36 2007/02/27 14:34:23 drmlipp
033: * Some refactoring to reduce cyclic dependencies.
034: *
035: * Revision 1.35 2007/02/27 10:56:33 drmlipp
036: * Removed left over attribute.
037: *
038: * Revision 1.34 2007/02/26 14:33:25 drmlipp
039: * Implemented filter.
040: *
041: * Revision 1.33 2007/02/25 20:39:22 mlipp
042: * Added process list filter.
043: *
044: * Revision 1.32 2007/02/22 22:32:44 mlipp
045: * Started process filter.
046: *
047: * Revision 1.31 2007/02/09 10:03:50 mlipp
048: * Improved exception handling.
049: *
050: * Revision 1.30 2007/02/07 14:26:38 mlipp
051: * Simplified.
052: *
053: * Revision 1.29 2006/12/04 14:18:42 drmlipp
054: * Added navigation between invoking and subprocess and fixed multiple deletes.
055: *
056: * Revision 1.28 2006/11/23 14:55:03 drmlipp
057: * Improved performance.
058: *
059: * Revision 1.27 2006/11/22 12:49:47 drmlipp
060: * Improved error handling.
061: *
062: * Revision 1.26 2006/11/21 18:38:29 drmlipp
063: * Improving exception handling.
064: *
065: * Revision 1.25 2006/10/04 09:27:54 drmlipp
066: * Using resource type information for display.
067: *
068: * Revision 1.24 2006/09/29 12:32:11 drmlipp
069: * Consistently using WfMOpen as projct name now.
070: *
071: * Revision 1.23 2006/09/21 14:26:29 drmlipp
072: * Fixed message reference.
073: *
074: * Revision 1.22 2006/09/15 11:43:04 drmlipp
075: * Minor improvements
076: *
077: * Revision 1.21 2006/09/14 20:24:12 mlipp
078: * Improved.
079: *
080: * Revision 1.20 2006/09/13 13:55:16 drmlipp
081: * Proceeding with assignments display.
082: *
083: * Revision 1.19 2006/09/13 11:02:03 drmlipp
084: * Started assignments display.
085: *
086: * Revision 1.18 2006/08/30 15:27:58 drmlipp
087: * Fixing navigational links.
088: *
089: * Revision 1.17 2006/07/17 14:57:35 drmlipp
090: * Started data display.
091: *
092: * Revision 1.16 2005/11/10 20:52:55 mlipp
093: * Fixed problem with classloader dependend Lifecycle access.
094: *
095: * Revision 1.15 2005/11/07 16:40:36 drmlipp
096: * Fixed sorting.
097: *
098: * Revision 1.14 2005/11/07 14:36:11 drmlipp
099: * Adapted to revised request attribute handling.
100: *
101: * Revision 1.13 2005/11/06 22:01:46 mlipp
102: * Got remove selected working.
103: *
104: * Revision 1.12 2005/11/04 16:29:49 drmlipp
105: * Select all implementation continued.
106: *
107: * Revision 1.11 2005/10/31 16:38:02 drmlipp
108: * Implementation of debug features continued.
109: *
110: * Revision 1.10 2005/10/24 08:09:31 drmlipp
111: * Simplified.
112: *
113: * Revision 1.9 2005/10/21 15:05:51 drmlipp
114: * Continued audit event display and cleaned up some things.
115: *
116: * Revision 1.8 2005/10/20 13:52:19 drmlipp
117: * Implementation of audit event display continued.
118: *
119: * Revision 1.7 2005/10/20 09:54:33 drmlipp
120: * Improved process selection
121: *
122: * Revision 1.6 2005/10/04 14:28:32 drmlipp
123: * Improved debug messages.
124: *
125: * Revision 1.5 2005/10/02 21:04:03 mlipp
126: * Added activity list sorting.
127: *
128: * Revision 1.4 2005/10/01 20:53:55 mlipp
129: * Improved status display.
130: *
131: * Revision 1.3 2005/09/29 21:59:08 mlipp
132: * Continued process detail view implementation.
133: *
134: * Revision 1.2 2005/09/28 15:12:41 drmlipp
135: * Updated MyFaces to 1.1.
136: *
137: * Revision 1.1 2005/09/23 14:55:03 drmlipp
138: * Basic process list implemented.
139: *
140: */
141: package de.danet.an.workflow.clients.mgmtportlets.process;
142:
143: import java.util.ArrayList;
144: import java.util.Collection;
145: import java.util.HashMap;
146: import java.util.Iterator;
147: import java.util.List;
148: import java.util.Locale;
149: import java.util.Map;
150: import java.util.ResourceBundle;
151: import java.util.Set;
152: import java.util.SortedSet;
153: import java.util.TreeSet;
154: import java.util.regex.Pattern;
155:
156: import java.io.Serializable;
157: import java.rmi.RemoteException;
158:
159: import javax.faces.application.FacesMessage;
160: import javax.faces.context.FacesContext;
161: import javax.faces.event.PhaseEvent;
162: import javax.faces.event.PhaseId;
163: import javax.faces.event.PhaseListener;
164: import javax.faces.model.DataModel;
165: import javax.faces.model.ListDataModel;
166: import javax.faces.model.SelectItem;
167:
168: import de.danet.an.util.BeanSorter;
169: import de.danet.an.util.Glob;
170: import de.danet.an.util.jsf.JSFUtil;
171:
172: import de.danet.an.workflow.api.Activity;
173: import de.danet.an.workflow.api.CannotRemoveException;
174: import de.danet.an.workflow.api.InvalidKeyException;
175: import de.danet.an.workflow.api.NoSuchResourceException;
176: import de.danet.an.workflow.api.Process;
177: import de.danet.an.workflow.api.ProcessDirectory;
178: import de.danet.an.workflow.api.WorkflowService;
179: import de.danet.an.workflow.clients.mgmtportlets.WorkflowServiceConnection;
180: import de.danet.an.workflow.omgcore.WfAssignment;
181: import de.danet.an.workflow.omgcore.WfResource;
182:
183: /**
184: * This class provides the central model for process management.
185: * <code>getProcesses</code> returns the process definition list.
186: * @author lipp
187: */
188: public class ProcessMgmt implements Serializable, PhaseListener {
189: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
190: .getLog(ProcessMgmt.class);
191:
192: private static String L10N_MSGS = "de.danet.an.workflow.clients.mgmtportlets.process.L10n";
193:
194: private WorkflowServiceConnection wsc = null;
195: private BeanSorter processSorter = null;
196: private transient ListDataModel processesAsModel = null;
197: private transient List resourceList = null;
198: private transient Map resourceMap = null;
199: private transient DataModel resourcesAsModel = null;
200: private transient boolean resourcesTyped = false;
201: private transient List assignedActivitiesList = null;
202: private transient DataModel assignmentsAsModel = null;
203: private transient List processNames = null;
204: private boolean reloadBeforeRendering = false;
205: private String selectedResourceKey = null;
206: private BeanSorter activitySorter = null;
207: private BeanSorter dataFieldSorter = null;
208: private BeanSorter auditEventSorter = null;
209: private BeanSorter resourceSorter = null;
210: private BeanSorter assignedActivitiesSorter = null;
211: private List selectedProcesses = new ArrayList();
212: private boolean showFilters = false;
213: private String nameFilter = "";
214: private String processKeyFilter = "";
215:
216: /**
217: * Create a new instance with all attributes initialized
218: * to defaults or the given values.
219: *
220: */
221: public ProcessMgmt() {
222: JSFUtil.addPhaseListenerForPortlet(this );
223: }
224:
225: /* (non-Javadoc)
226: * @see javax.faces.event.PhaseListener#getPhaseId()
227: */
228: public PhaseId getPhaseId() {
229: return PhaseId.ANY_PHASE;
230: }
231:
232: /* (non-Javadoc)
233: * @see javax.faces.event.PhaseListener#beforePhase
234: */
235: public void beforePhase(PhaseEvent evt) {
236: if (evt.getPhaseId().equals(PhaseId.APPLY_REQUEST_VALUES)) {
237: selectedProcesses.clear();
238: } else if (evt.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
239: if (reloadBeforeRendering) {
240: // Get updated process list before rendering
241: // (has have been modified by action)
242: processesAsModel = null;
243: processNames = null;
244: resourceList = null;
245: resourceMap = null;
246: resourcesAsModel = null;
247: assignedActivitiesList = null;
248: assignmentsAsModel = null;
249: reloadBeforeRendering = false;
250: }
251: }
252: }
253:
254: /* (non-Javadoc)
255: * @see javax.faces.event.PhaseListener#afterPhase
256: */
257: public void afterPhase(PhaseEvent evt) {
258: if (evt.getPhaseId().equals(PhaseId.INVOKE_APPLICATION)) {
259: selectedProcesses.clear();
260: } else if (evt.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
261: processesAsModel = null;
262: processNames = null;
263: resourceList = null;
264: resourceMap = null;
265: resourcesAsModel = null;
266: assignedActivitiesList = null;
267: assignmentsAsModel = null;
268: }
269: }
270:
271: /**
272: * @return Returns the workflow service connection.
273: */
274: public WorkflowServiceConnection getWorkflowServiceConnection() {
275: return wsc;
276: }
277:
278: /**
279: * @param wsc The workflow service connection to set.
280: */
281: public void setWorkflowServiceConnection(
282: WorkflowServiceConnection wsc) {
283: this .wsc = wsc;
284: if (logger.isDebugEnabled()) {
285: logger.debug("Workflow service connection set to: " + wsc);
286: }
287: }
288:
289: /**
290: * @return Returns the sorter.
291: */
292: public BeanSorter getProcessSorter() {
293: return processSorter;
294: }
295:
296: /**
297: * @param sorter The sorter to set.
298: */
299: public void setProcessSorter(BeanSorter sorter) {
300: this .processSorter = sorter;
301: }
302:
303: /**
304: * @return Returns the activitySorter.
305: */
306: public BeanSorter getActivitySorter() {
307: return activitySorter;
308: }
309:
310: /**
311: * @param activitySorter The activitySorter to set.
312: */
313: public void setActivitySorter(BeanSorter activitySorter) {
314: this .activitySorter = activitySorter;
315: }
316:
317: /**
318: * @return Returns the dataFieldSorter.
319: */
320: public BeanSorter getDataFieldSorter() {
321: return dataFieldSorter;
322: }
323:
324: /**
325: * @param dataFieldSorter The dataFieldSorter to set.
326: */
327: public void setDataFieldSorter(BeanSorter dataFieldSorter) {
328: this .dataFieldSorter = dataFieldSorter;
329: }
330:
331: /**
332: * @return Returns the auditEventSorter.
333: */
334: public BeanSorter getAuditEventSorter() {
335: return auditEventSorter;
336: }
337:
338: /**
339: * @param auditEventSorter The auditEventSorter to set.
340: */
341: public void setAuditEventSorter(BeanSorter auditEventSorter) {
342: this .auditEventSorter = auditEventSorter;
343: }
344:
345: /**
346: * @return Returns the principalsSorter.
347: */
348: public BeanSorter getResourceSorter() {
349: return resourceSorter;
350: }
351:
352: /**
353: * @param principalsSorter The principalsSorter to set.
354: */
355: public void setResourceSorter(BeanSorter principalsSorter) {
356: this .resourceSorter = principalsSorter;
357: }
358:
359: /**
360: * @return Returns the assignedActivitiesSorter.
361: */
362: public BeanSorter getAssignedActivitiesSorter() {
363: return assignedActivitiesSorter;
364: }
365:
366: /**
367: * @param assignedActivitiesSorter The assignedActivitiesSorter to set.
368: */
369: public void setAssignedActivitiesSorter(
370: BeanSorter assignedActivitiesSorter) {
371: this .assignedActivitiesSorter = assignedActivitiesSorter;
372: }
373:
374: /**
375: * @return the list of processes
376: */
377: public DataModel getProcesses() {
378: if (processesAsModel == null) {
379: logger.debug("Retrieving process list");
380: ProcessDirectory pd = null;
381: List processList = new ArrayList();
382: Set processNamesSet = new TreeSet();
383: try {
384: pd = wsc.getWorkflowService().processDirectory();
385: Collection defs = pd.processes();
386: Pattern procKeyPattern = null;
387: if (processKeyFilter.length() > 0
388: && Glob.isGlobExpression(processKeyFilter)) {
389: procKeyPattern = Pattern.compile(Glob
390: .globToRegexp(processKeyFilter));
391: }
392: for (Iterator i = defs.iterator(); i.hasNext();) {
393: Process proc = (Process) i.next();
394: ProcessWrapper wrappedProc = new ProcessWrapper(
395: proc);
396: processNamesSet.add(wrappedProc.getName());
397: if (nameFilter.length() > 0
398: && !wrappedProc.getName()
399: .equals(nameFilter)) {
400: continue;
401: }
402: if (processKeyFilter.length() > 0) {
403: if (procKeyPattern == null) {
404: if (!wrappedProc.getProcessKey().equals(
405: processKeyFilter)) {
406: continue;
407: }
408: } else if (!procKeyPattern.matcher(
409: wrappedProc.getProcessKey()).matches()) {
410: continue;
411: }
412: }
413: processList.add(wrappedProc);
414: }
415: } catch (RemoteException e) {
416: JSFUtil.addMessage(FacesMessage.SEVERITY_ERROR,
417: L10N_MSGS, "resourceCurrentlyUnavailable",
418: null, e);
419: } finally {
420: wsc.getWorkflowService().release(pd);
421: }
422: if (processSorter != null) {
423: processSorter.sort(processList);
424: }
425: processesAsModel = new ListDataModel(processList);
426: processNames = new ArrayList();
427: processNames.add(new SelectItem(""));
428: for (Iterator i = processNamesSet.iterator(); i.hasNext();) {
429: processNames.add(new SelectItem(i.next()));
430: }
431: } else {
432: if (processSorter != null && processSorter.isModified()) {
433: processSorter.sort((List) processesAsModel
434: .getWrappedData());
435: }
436: }
437: return processesAsModel;
438: }
439:
440: /**
441: * Get the process names.
442: * @return process names as set of strings.
443: */
444: public List getProcessNames() {
445: if (processNames == null) {
446: getProcesses();
447: }
448: return processNames;
449: }
450:
451: /**
452: * @return number of processes in list.
453: */
454: public int getProcessCount() {
455: return getProcesses().getRowCount();
456: }
457:
458: /**
459: * @return Returns the allSelected.
460: */
461: public boolean isAllSelected() {
462: return false;
463: }
464:
465: /**
466: * @param allSelected The allSelected to set.
467: */
468: public void setAllSelected(boolean allSelected) {
469: if (!allSelected) {
470: return;
471: }
472: FacesContext fc = FacesContext.getCurrentInstance();
473: fc.getExternalContext().getRequestMap().put(
474: "processAllSelection", Boolean.TRUE);
475: }
476:
477: /**
478: * @param process the process to add
479: */
480: public void addSelected(Process process) {
481: selectedProcesses.add(process);
482: }
483:
484: /**
485: * Remove given process.
486: */
487: public void remove(Process process) throws RemoteException {
488: ProcessDirectory procDir = wsc.getWorkflowService()
489: .processDirectory();
490: try {
491: procDir.removeProcess(process);
492: } catch (CannotRemoveException e) {
493: JSFUtil.addMessage(FacesMessage.SEVERITY_ERROR, L10N_MSGS,
494: "cannotRemove", null, e);
495: }
496: reloadBeforeRendering = true;
497: }
498:
499: /**
500: * Remove selected processes.
501: */
502: public String removeSelected() throws RemoteException {
503: ProcessDirectory procDir = wsc.getWorkflowService()
504: .processDirectory();
505: for (Iterator i = selectedProcesses.iterator(); i.hasNext();) {
506: Process process = (Process) i.next();
507: try {
508: procDir.removeProcess(process);
509: } catch (CannotRemoveException e) {
510: // Probably removed by other user
511: logger.debug(e.getMessage(), e);
512: }
513: }
514: reloadBeforeRendering = true;
515: return null;
516: }
517:
518: /**
519: * Action for going to process list immediately.
520: */
521: public String showProcessList() {
522: return "showProcessList";
523: }
524:
525: /**
526: * @return the list of resources
527: */
528: public DataModel getResources() {
529: if (resourcesAsModel == null) {
530: if (resourceList != null) {
531: logger.debug("Using previously created process list");
532: if (resourceSorter != null
533: && resourceSorter.isModified()) {
534: logger.debug("Re-sorting");
535: resourceSorter.sort(resourceList);
536: }
537: } else {
538: logger.debug("Retrieving resource list");
539: resourceList = new ArrayList();
540: resourceMap = new HashMap();
541: try {
542: Collection resources = wsc.getWorkflowService()
543: .knownResources();
544: Locale locale = JSFUtil.activeLocale();
545: ResourceBundle rb = ResourceBundle.getBundle(
546: "de.danet.an.workflow.clients.mgmtportlets.process"
547: + ".L10n", locale,
548: ProcessMgmt.class.getClassLoader());
549: resourcesTyped = false;
550: for (Iterator i = resources.iterator(); i.hasNext();) {
551: ResourceWrapper res = new ResourceWrapper(
552: (WfResource) i.next(), rb);
553: if (res.isTyped()) {
554: resourcesTyped = true;
555: }
556: resourceList.add(res);
557: resourceMap.put(res.getKey(), res);
558: }
559: } catch (RemoteException e) {
560: JSFUtil.addMessage(FacesMessage.SEVERITY_ERROR,
561: L10N_MSGS, "resourceCurrentlyUnavailable",
562: null, e);
563: }
564: if (resourceSorter != null) {
565: resourceSorter.sort(resourceList);
566: }
567: }
568: resourcesAsModel = new ListDataModel(resourceList);
569: } else {
570: if (resourceSorter != null && resourceSorter.isModified()) {
571: resourceSorter.sort(resourceList);
572: }
573: }
574: return resourcesAsModel;
575: }
576:
577: /**
578: * Return if resources are typed.
579: */
580: public boolean isResourcesTyped() {
581: if (resourcesAsModel == null) {
582: getResources();
583: }
584: return resourcesTyped;
585: }
586:
587: /**
588: * @return Returns the selected resource's key.
589: */
590: public String getSelectedResourceKey() {
591: return selectedResourceKey;
592: }
593:
594: /**
595: * @param selectedResource The selectedResource to set.
596: */
597: public void setSelectedResourceKey(String selectedResource) {
598: this .selectedResourceKey = selectedResource;
599: assignmentsAsModel = null;
600: assignedActivitiesList = null;
601: }
602:
603: /**
604: * @return Returns the selected resource's key.
605: */
606: public ResourceWrapper getSelectedResource() {
607: if (selectedResourceKey == null) {
608: return null;
609: }
610: getResources(); // make sure that the resourceMap is initialized
611: return (ResourceWrapper) resourceMap.get(selectedResourceKey);
612: }
613:
614: /**
615: * @return the list of assigned activities
616: */
617: public DataModel getAssignedActivities() {
618: if (assignmentsAsModel == null) {
619: if (assignedActivitiesList != null) {
620: logger
621: .debug("Using previously created assignments list");
622: if (assignedActivitiesSorter != null
623: && assignedActivitiesSorter.isModified()) {
624: logger.debug("Re-sorting");
625: assignedActivitiesSorter
626: .sort(assignedActivitiesList);
627: }
628: } else {
629: logger.debug("Retrieving assignments list");
630: assignedActivitiesList = new ArrayList();
631: if (selectedResourceKey != null) {
632: try {
633: WorkflowService wfs = wsc.getWorkflowService();
634: WfResource resource = wfs
635: .resourceByKey(selectedResourceKey);
636: Collection assignments = resource.workItems();
637: for (Iterator i = assignments.iterator(); i
638: .hasNext();) {
639: WfAssignment assignment = (WfAssignment) i
640: .next();
641: assignedActivitiesList
642: .add(new ActivityWrapper(wfs,
643: (Activity) assignment
644: .activity()));
645: }
646: } catch (RemoteException e) {
647: JSFUtil
648: .addMessage(
649: FacesMessage.SEVERITY_ERROR,
650: L10N_MSGS,
651: "resourceCurrentlyUnavailable",
652: null, e);
653: } catch (InvalidKeyException e) {
654: selectedResourceKey = null;
655: }
656: }
657: if (assignedActivitiesSorter != null) {
658: assignedActivitiesSorter
659: .sort(assignedActivitiesList);
660: }
661: }
662: assignmentsAsModel = new ListDataModel(
663: assignedActivitiesList);
664: } else {
665: if (assignedActivitiesSorter != null
666: && assignedActivitiesSorter.isModified()) {
667: assignedActivitiesSorter.sort(assignedActivitiesList);
668: }
669: }
670: return assignmentsAsModel;
671: }
672:
673: /**
674: * Action for going to resurces list immediately.
675: */
676: public String showResources() {
677: return "showResources";
678: }
679:
680: /**
681: * Show filters.
682: */
683: public String showFilters() {
684: setShowFilters(true);
685: setNameFilter("");
686: setProcessKeyFilter("");
687: return null;
688: }
689:
690: /**
691: * Hide filters.
692: */
693: public String hideFilters() {
694: setShowFilters(false);
695: setNameFilter("");
696: setProcessKeyFilter("");
697: return null;
698: }
699:
700: /**
701: * @return Returns the showFilters.
702: */
703: public boolean isShowFilters() {
704: return showFilters;
705: }
706:
707: /**
708: * @param showFilters The showFilters to set.
709: */
710: public void setShowFilters(boolean showFilters) {
711: this .showFilters = showFilters;
712: }
713:
714: /**
715: * @return Returns the nameFilter.
716: */
717: public String getNameFilter() {
718: return nameFilter;
719: }
720:
721: /**
722: * @param nameFilter The nameFilter to set.
723: */
724: public void setNameFilter(String nameFilter) {
725: // Normalize
726: if (nameFilter == null) {
727: nameFilter = "";
728: }
729: if (!this .nameFilter.equals(nameFilter)) {
730: this .nameFilter = nameFilter;
731: reloadBeforeRendering = true;
732: }
733: }
734:
735: /**
736: * @return Returns the processKeyFilter.
737: */
738: public String getProcessKeyFilter() {
739: return processKeyFilter;
740: }
741:
742: /**
743: * @param processKeyFilter The processKeyFilter to set.
744: */
745: public void setProcessKeyFilter(String processKeyFilter) {
746: // Normalize
747: if (processKeyFilter == null) {
748: processKeyFilter = "";
749: }
750: if (!this .processKeyFilter.equals(processKeyFilter)) {
751: this .processKeyFilter = processKeyFilter;
752: reloadBeforeRendering = true;
753: }
754: }
755:
756: /**
757: * Apply filters.
758: */
759: public String applyFilters() {
760: return null;
761: }
762:
763: }
|