/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.bpm.console.client.model;
import org.jboss.bpm.console.client.model.TokenReference;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;
/**
* @author Heiko.Braun <heiko.braun@jboss.com>
*/
@XmlRootElement(name="processInstance")
public class ProcessInstanceRef
{
private String id;
private String definitionId;
private String key;
/**
* the active state of an instance
*/
public static enum STATE {RUNNING, SUSPENDED, ENDED};
/**
* the end state of an instance
*/
public static enum RESULT {COMPLETED, FAILED, ERROR, EXITED, OBSOLETE};
private Date startDate;
private Date endDate;
private boolean suspended;
private RESULT endResult;
private transient Lifecycle lifecycle;
private TokenReference rootToken;
public ProcessInstanceRef()
{
initLifecycle();
}
public ProcessInstanceRef(String id, String processDefinitionId, Date startDate, Date endDate, boolean suspended)
{
if(null==startDate)
throw new IllegalArgumentException("An instance requires a start date");
if(endDate!=null && suspended)
throw new IllegalArgumentException("An instance cannot be ended and suspended at the same time");
this.id = id;
this.definitionId = processDefinitionId;
this.startDate = startDate;
this.endDate = endDate;
this.suspended = suspended;
initLifecycle();
}
/**
* If not ENDED or SUSPENDED the instance is RUNNING
*/
private void initLifecycle()
{
if(hasEnded())
this.lifecycle = new Lifecycle(this, STATE.ENDED);
else if(isSuspended())
this.lifecycle = new Lifecycle(this, STATE.SUSPENDED);
else
this.lifecycle = new Lifecycle(this, STATE.RUNNING);
}
@XmlElement(name = "instanceId")
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
@XmlElement(name = "definitionId")
public String getDefinitionId()
{
return definitionId;
}
public void setDefinitionId(String definitionId)
{
this.definitionId = definitionId;
}
@XmlElement(name = "key")
public String getKey()
{
return key !=null ? key : "";
}
public void setKey(String key)
{
this.key = key;
}
@XmlElement(name = "status")
public STATE getState()
{
return this.lifecycle.getState();
}
public void setState(String nextState)
{
setState(STATE.valueOf(nextState));
}
public void setState(STATE nextState)
{
this.lifecycle = this.lifecycle.transitionTo(nextState);
}
@XmlElement(name = "start")
public Date getStartDate()
{
return startDate;
}
public void setStartDate(Date startDate)
{
this.startDate = startDate;
}
@XmlElement(name = "end")
public Date getEndDate()
{
return endDate;
}
public void setEndDate(Date endDate)
{
this.endDate = endDate;
}
public boolean isRunning()
{
return this.startDate!=null && !isSuspended();
}
public boolean hasEnded()
{
return this.startDate!=null
&& this.endDate!=null;
}
public boolean isSuspended()
{
return null==this.endDate && suspended;
}
private class Lifecycle
{
private STATE current;
private ProcessInstanceRef instance;
public Lifecycle(ProcessInstanceRef instance, STATE current)
{
this.instance = instance;
this.current = current;
}
public Lifecycle transitionTo(STATE next)
{
Lifecycle nextLifecycle = null;
switch(next)
{
case SUSPENDED: // only RUNNING instances can be SUSPENDED
if(STATE.RUNNING.equals(current))
{
nextLifecycle = new Lifecycle(instance, next);
instance.suspended = true;
break;
}
else
{
throw new IllegalTransitionException(current, next);
}
case ENDED: // both RUNNING and SUSPENDED instances can be ENDED
if(STATE.RUNNING.equals(current) || STATE.SUSPENDED.equals(current))
{
nextLifecycle = new Lifecycle(instance, next);
instance.suspended = false;
instance.endDate = new Date();
break;
}
else
{
throw new IllegalTransitionException(current, next);
}
case RUNNING: // only SUSPENDED instances can become RUNNING
if(STATE.SUSPENDED.equals(current))
{
nextLifecycle = new Lifecycle(instance, next);
instance.suspended = false;
break;
}
else
{
throw new IllegalTransitionException(current, next);
}
default:
throw new IllegalTransitionException(current, next);
}
return nextLifecycle;
}
public STATE getState()
{
return current;
}
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Lifecycle lifecycle = (Lifecycle) o;
if (current != lifecycle.current) return false;
return true;
}
public int hashCode()
{
int result;
result = (current != null ? current.hashCode() : 0);
return result;
}
}
private class IllegalTransitionException extends IllegalArgumentException
{
public IllegalTransitionException(STATE current, STATE next)
{
super("Illegal transition current " + current + " next " + next);
}
}
public TokenReference getRootToken()
{
return rootToken;
}
public void setRootToken(TokenReference rootToken)
{
this.rootToken = rootToken;
}
// it's actually just used for unmarshalling, TODO: fix it
public void setSuspended(boolean suspended)
{
this.suspended = suspended;
initLifecycle();
}
public RESULT getEndResult()
{
return endResult;
}
public void setEndResult(RESULT endResult)
{
if(getState()!=STATE.ENDED)
throw new IllegalArgumentException("Cannot set end result in state "+getState());
this.endResult = endResult;
}
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProcessInstanceRef that = (ProcessInstanceRef) o;
if (definitionId != null ? !definitionId.equals(that.definitionId) : that.definitionId != null) return false;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (key != null ? !key.equals(that.key) : that.key != null) return false;
return true;
}
public int hashCode()
{
int result;
result = (id != null ? id.hashCode() : 0);
result = 31 * result + (definitionId != null ? definitionId.hashCode() : 0);
result = 31 * result + (key != null ? key.hashCode() : 0);
return result;
}
}