/*
* This file is part of the WfMOpen project.
* Copyright (C) 2005 Danet GmbH (www.danet.de), BU TEL.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: ProcessWrapper.java 2893 2009-01-20 17:02:33Z drmlipp $
*
* $Log$
* Revision 1.33 2007/03/01 13:10:26 drmlipp
* Added special handling for empty names.
*
* Revision 1.32 2006/12/04 14:18:42 drmlipp
* Added navigation between invoking and subprocess and fixed multiple deletes.
*
* Revision 1.31 2006/12/03 22:45:42 mlipp
* Obtain requester information.
*
* Revision 1.30 2006/11/23 16:40:20 drmlipp
* Optimized.
*
* Revision 1.29 2006/11/23 08:58:45 drmlipp
* Moved signature retrieval to mutable wrapper (only needed there).
*
* Revision 1.28 2006/11/22 12:49:47 drmlipp
* Improved error handling.
*
* Revision 1.27 2006/11/21 18:38:29 drmlipp
* Improving exception handling.
*
* Revision 1.26 2006/09/29 12:32:11 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.25 2006/09/15 11:43:04 drmlipp
* Minor improvements
*
* Revision 1.24 2006/09/06 09:31:06 drmlipp
* Cleaned up event display.
*
* Revision 1.23 2006/07/18 16:36:51 mlipp
* Added String and Integer data input fileds.
*
* Revision 1.22 2006/07/17 14:57:35 drmlipp
* Started data display.
*
* Revision 1.21 2005/11/07 14:36:11 drmlipp
* Adapted to revised request attribute handling.
*
* Revision 1.20 2005/11/06 22:01:46 mlipp
* Got remove selected working.
*
* Revision 1.19 2005/11/03 22:27:38 mlipp
* Started multiple selection implementation.
*
* Revision 1.18 2005/11/03 20:50:17 mlipp
* Simplified a bit.
*
* Revision 1.17 2005/10/21 15:05:51 drmlipp
* Continued audit event display and cleaned up some things.
*
* Revision 1.16 2005/10/20 13:52:19 drmlipp
* Implementation of audit event display continued.
*
* Revision 1.15 2005/10/19 20:52:07 mlipp
* Various fixes.
*
* Revision 1.14 2005/10/19 14:36:40 drmlipp
* Improved process editing.
*
* Revision 1.13 2005/10/18 20:54:31 mlipp
* Finished process state changing.
*
* Revision 1.12 2005/10/18 15:28:16 drmlipp
* Started editable process state.
*
* Revision 1.11 2005/10/14 12:45:35 drmlipp
* Added information.
*
* Revision 1.10 2005/10/12 15:16:28 drmlipp
* Implementation continued.
*
* Revision 1.9 2005/10/04 14:28:32 drmlipp
* Improved debug messages.
*
* Revision 1.8 2005/10/02 21:04:03 mlipp
* Added activity list sorting.
*
* Revision 1.7 2005/10/01 20:53:55 mlipp
* Improved status display.
*
* Revision 1.6 2005/09/30 21:48:58 mlipp
* Basic process detail display working.
*
* Revision 1.5 2005/09/29 21:59:08 mlipp
* Continued process detail view implementation.
*
* Revision 1.4 2005/09/27 17:05:15 drmlipp
* Process display continued.
*
* Revision 1.3 2005/09/26 21:34:01 mlipp
* Started detail view.
*
* Revision 1.2 2005/09/23 21:03:31 mlipp
* Added attributes.
*
* Revision 1.1 2005/09/23 14:55:03 drmlipp
* Basic process list implemented.
*
*/
package de.danet.an.workflow.clients.mgmtportlets.process;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import de.danet.an.util.BeanSorter;
import de.danet.an.workflow.api.Activity;
import de.danet.an.workflow.api.InvalidKeyException;
import de.danet.an.workflow.api.MethodInvocationBatch;
import de.danet.an.workflow.api.Process;
import de.danet.an.workflow.api.ProcessDirectory;
import de.danet.an.workflow.api.WorkflowService;
import de.danet.an.workflow.clients.mgmtportlets.WorkflowServiceConnection;
import de.danet.an.workflow.omgcore.WfActivity;
import de.danet.an.workflow.omgcore.WfRequester;
/**
* A wrapper class that makes processes look like JavaBeans.
*/
public class ProcessWrapper implements Serializable {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog (ProcessWrapper.class);
protected static String L10N_MSGS
= "de.danet.an.workflow.clients.mgmtportlets.process.L10n";
private transient Process processCache;
private String packageId;
private String packageName;
private String processId;
private String processName;
private String mgrName = null;
private String processKey = null;;
private String name;
private int priority;
private String state;
private Date createTime;
private Date lastStateTime;
private String invokingMgrName = null;
private String invokingProcKey = null;
private String invokingActName = null;
private String invokingActKey = null;
private transient DataModel activities = null;
private BeanSorter activitySorter = null;
private boolean selected = false;
/**
* Create a new instance for the given process definition.
* @param pd the process definition to wrap
*/
public ProcessWrapper (String processMgrName, String processKey)
throws RemoteException {
this.mgrName = processMgrName;
this.processKey = processKey;
update();
}
/**
* Create a new instance for the given process definition.
* @param pd the process definition to wrap
*/
public ProcessWrapper (Process proc)
throws RemoteException {
this.processCache = proc;
update();
}
/**
* Update data if not already updated in this lifecycle.
* @throws RemoteException
*/
protected void update() throws RemoteException {
MethodInvocationBatch mib = new MethodInvocationBatch ();
WorkflowService wfs = WorkflowServiceConnection
.instance("workflowServiceConnection").getWorkflowService();
if (processCache == null) {
ProcessDirectory pd = wfs.processDirectory();
mib.addInvocation
(pd, "lookupProcess",
new String[] {"java.lang.String", "java.lang.String"},
new Object[] {mgrName, processKey});
mib.addInvocation(-1, "processDefinition", null, null, false);
mib.addInvocation(-1, "packageId", null, null, false);
mib.addInvocation(-2, "packageName", null, null, false);
mib.addInvocation(-3, "processId", null, null, false);
mib.addInvocation(-4, "processName", null, null, true);
mib.addInvocation(-5, "name", null, null, false);
mib.addInvocation(-6, "priority", null, null, false);
mib.addInvocation(-7, "state", null, null, false);
mib.addInvocation(-8, "createTime", null, null, false);
mib.addInvocation(-9, "lastStateTime", null, null, false);
mib.addInvocation(-10, "requester", null, null, false);
} else {
mib.addInvocation(processCache, "key", null, null);
mib.addInvocation
(processCache, "processDefinition", null, null);
mib.addInvocation(-1, "mgrName", null, null, false);
mib.addInvocation(-2, "packageId", null, null, false);
mib.addInvocation(-3, "packageName", null, null, false);
mib.addInvocation(-4, "processId", null, null, false);
mib.addInvocation(-5, "processName", null, null, true);
mib.addInvocation(processCache, "name", null, null);
mib.addInvocation(processCache, "priority", null, null);
mib.addInvocation(processCache, "state", null, null);
mib.addInvocation(processCache, "createTime", null, null);
mib.addInvocation(processCache, "lastStateTime", null, null);
mib.addInvocation(processCache, "requester", null, null);
}
MethodInvocationBatch.Result mir = null;
try {
mir = (MethodInvocationBatch.Result)wfs.executeBatch(mib);
} catch (InvocationTargetException e) {
throw (IllegalStateException)
(new IllegalStateException (e.getMessage())).initCause(e);
}
if (mir.hasExceptions ()) {
Exception e = mir.firstException ();
if (e instanceof RemoteException) {
throw (RemoteException)e;
}
throw (IllegalStateException)
(new IllegalStateException(e.getMessage())).initCause(e);
}
int resPos = 0;
if (processCache == null) {
processCache = (Process)mir.result(resPos++);
} else {
processKey = mir.resultAsString(resPos++);
mgrName = mir.resultAsString(resPos++);
}
packageId = mir.resultAsString(resPos++);
packageName = mir.resultAsString(resPos++);
processId = mir.resultAsString(resPos++);
processName = mir.resultAsString(resPos++);
name = mir.resultAsString(resPos++);
priority = mir.resultAsInt(resPos++);
state = mir.resultAsString(resPos++);
createTime = mir.resultAsDate(resPos++);
lastStateTime = mir.resultAsDate(resPos++);
WfRequester requester = (WfRequester)mir.result(resPos++);
if (requester instanceof WfActivity) {
mib = new MethodInvocationBatch ();
mib.addInvocation(requester, "name", null, null);
mib.addInvocation(requester, "key", null, null);
mib.addInvocation(requester, "container", null, null);
mib.addInvocation(-1, "manager", null, null, false);
mib.addInvocation(-1, "name", null, null, true);
mib.addInvocation(-2, "key", null, null, true);
mir = null;
try {
mir = (MethodInvocationBatch.Result)wfs.executeBatch(mib);
} catch (InvocationTargetException e) {
throw (IllegalStateException)
(new IllegalStateException (e.getMessage())).initCause(e);
}
if (mir.hasExceptions ()) {
Exception e = mir.firstException ();
if (e instanceof RemoteException) {
throw (RemoteException)e;
}
throw (IllegalStateException)
(new IllegalStateException(e.getMessage())).initCause(e);
}
invokingActName = mir.resultAsString(0);
invokingActKey = mir.resultAsString(1);
invokingMgrName = mir.resultAsString(2);
invokingProcKey = mir.resultAsString(3);
}
}
/**
* Return the process management bean.
* @return the result
*/
protected ProcessMgmt processMgmt () {
FacesContext fc = FacesContext.getCurrentInstance();
return (ProcessMgmt)fc.getApplication()
.getVariableResolver().resolveVariable(fc, "processMgmt");
}
/**
* @return the process
*/
public Process process() throws RemoteException {
if (processCache == null) {
try {
WorkflowService wfs = WorkflowServiceConnection
.instance("workflowServiceConnection").getWorkflowService();
ProcessDirectory pd = wfs.processDirectory();
processCache = pd.lookupProcess(mgrName, processKey);
} catch (InvalidKeyException e) {
return null;
}
}
return processCache;
}
/**
* @return Returns the packageName.
*/
public String getPackageName() {
return packageName == null || packageName.length() == 0
? "(" + packageId + ")" : packageName;
}
/**
* @return Returns the processName.
*/
public String getProcessName() {
return processName == null || processName.length() == 0
? "(" + processId + ")" : processName;
}
/**
* @return Returns the mgrName.
*/
public String getMgrName() {
return mgrName;
}
/**
* Returns the process name.
* @return the process name
*/
public String getName () {
return name != null && name.length() > 0
? name : "(" + processKey + ")";
}
/**
* @return Returns the priority.
*/
public int getPriority() {
return priority;
}
/**
* @param priority The priority to set.
*/
public void setPriority(int priority) {
this.priority = priority;
}
/**
* @return Returns the createTime.
*/
public Date getCreateTime() {
return createTime;
}
/**
* @return Returns the lastStateTime.
*/
public Date getLastStateTime() {
return lastStateTime;
}
/**
* @return Returns the processKey.
*/
public String getProcessKey() {
return processKey;
}
/**
* @return Returns the state.
*/
public String getStateName() {
return StateNameMapper.mapState(state);
}
/**
* @return Returns the state.
*/
public String getState() {
return state;
}
/**
* @param state The state to set.
*/
public void setState(String state) {
this.state = state;
}
/**
* Return if process is removable.
*/
public boolean isRemovable () {
return state.startsWith("closed.");
}
/**
* Return if process is updatable.
*/
public boolean isUpdatable () {
return !state.startsWith("closed.");
}
/**
* @return URL of state icon or null
*/
public String getStateIconUrl () throws RemoteException {
return StateNameMapper.stateIconUrl (getState());
}
/**
* @return the activities
*/
public DataModel getActivities() throws RemoteException {
FacesContext fc = FacesContext.getCurrentInstance();
if (activitySorter == null) {
activitySorter = processMgmt().getActivitySorter();
}
if (activities == null) {
if (logger.isDebugEnabled()) {
logger.debug("Retrieving activity list of process " + this);
}
WorkflowService wfs = ((WorkflowServiceConnection)
fc.getApplication().getVariableResolver()
.resolveVariable(fc, "workflowServiceConnection"))
.getWorkflowService();
List actList = new ArrayList();
for (Iterator i = process().steps().iterator(); i.hasNext();) {
Activity act = (Activity)i.next();
actList.add(new ActivityWrapper(wfs, act));
}
activitySorter.sort (actList);
activities = new ListDataModel (actList);
} else {
logger.debug ("Re-using activities");
if (activitySorter.isModified ()) {
activitySorter.sort ((List)activities.getWrappedData());
}
}
return activities;
}
/**
* @return invoker's name or <code>null</code>
*/
public String getRequester () {
if (invokingActKey == null) {
return null;
}
if (invokingActName != null) {
return invokingActName;
}
return "(" + invokingActKey + ")";
}
/**
* @return outcome
*/
public String showDetail () {
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getSessionMap().put
("processSelection",
new ProcessSelection(mgrName, processKey));
return "showProcessDetail";
}
/**
* @return outcome
*/
public String showRequesterDetail () {
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getSessionMap().put
("processSelection",
new ProcessSelection(invokingMgrName, invokingProcKey));
return "showProcessDetail";
}
/**
* Remove.
*/
public String remove () throws RemoteException {
processMgmt().remove(process());
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getSessionMap().remove ("processSelection");
return "showProcessList";
}
public String toString () {
return "ProcessWrapper[name=" + name
+ ",processKey=" + processKey + "]";
}
/**
* @return Returns the selected.
*/
public boolean isSelected() throws RemoteException {
FacesContext fc = FacesContext.getCurrentInstance();
if (fc.getExternalContext().getRequestMap()
.containsKey("processAllSelection")) {
return isRemovable();
}
return selected;
}
/**
* @param selected The selected to set.
*/
public void setSelected(boolean selected) throws RemoteException {
if (!this.selected && selected) {
processMgmt().addSelected (process());
}
this.selected = selected;
}
}