polish of view scope handling

This commit is contained in:
Keith Donald
2008-03-31 21:15:03 +00:00
parent 3a27bdaac2
commit 7ea4f6277c
3 changed files with 91 additions and 73 deletions

View File

@@ -140,6 +140,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
*/ */
private Serializable messagesMemento; private Serializable messagesMemento;
/**
* The flow execution outcome event.
*/
private transient Event outcome; private transient Event outcome;
/** /**
@@ -154,20 +157,26 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
* @param flow the root flow of this flow execution * @param flow the root flow of this flow execution
*/ */
public FlowExecutionImpl(Flow flow) { public FlowExecutionImpl(Flow flow) {
setFlow(flow); Assert.notNull(flow, "The flow definition is required");
this.flow = flow;
this.listeners = new FlowExecutionListeners(); this.listeners = new FlowExecutionListeners();
this.attributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP; this.attributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP;
this.flowSessions = new LinkedList(); this.flowSessions = new LinkedList();
this.conversationScope = new LocalAttributeMap(); this.conversationScope = new LocalAttributeMap();
} }
/**
* Package private constructor only useful for testing restoration behavior for this object.
* @param flowId the flow id
* @param flowSessions the flow sessions
*/
FlowExecutionImpl(String flowId, LinkedList flowSessions) { FlowExecutionImpl(String flowId, LinkedList flowSessions) {
this.flowId = flowId; this.flowId = flowId;
this.flowSessions = flowSessions; this.flowSessions = flowSessions;
} }
public String getCaption() { public String getCaption() {
return "execution of '" + flowId + "'"; return "execution of '" + flow.getId() + "'";
} }
// implementing FlowExecutionContext // implementing FlowExecutionContext
@@ -343,13 +352,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
listeners.fireStateEntering(context, newState); listeners.fireStateEntering(context, newState);
FlowSessionImpl session = getActiveSessionInternal(); FlowSessionImpl session = getActiveSessionInternal();
State previousState = (State) session.getState(); State previousState = (State) session.getState();
if (previousState != null && previousState.isViewState()) { session.setCurrentState(newState);
session.destroyViewScope();
}
session.setState(newState);
if (newState.isViewState()) {
session.initViewScope();
}
listeners.fireStateEntered(context, previousState); listeners.fireStateEntered(context, previousState);
} }
@@ -370,7 +373,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
flowSessions.removeLast(); flowSessions.removeLast();
listeners.fireSessionEnded(context, session, output); listeners.fireSessionEnded(context, session, output);
if (hasEnded()) { if (hasEnded()) {
this.outcome = new Event(this, session.getState().getId(), output); outcome = new Event(this, session.getState().getId(), output);
} }
return session; return session;
} }
@@ -386,7 +389,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
// package private setters for restoring transient state used by FlowExecutionImplServicesConfigurer // package private setters for restoring transient state used by FlowExecutionImplServicesConfigurer
FlowExecutionListener[] getListeners() { FlowExecutionListener[] getListeners() {
return this.listeners.getArray(); return listeners.getArray();
} }
void setListeners(FlowExecutionListener[] listeners) { void setListeners(FlowExecutionListener[] listeners) {
@@ -407,28 +410,6 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
// Used by FlowExecutionImplStateRestorer // Used by FlowExecutionImplStateRestorer
/**
* Restore the flow definition of this flow execution.
*/
void setFlow(Flow flow) {
this.flow = flow;
this.flowId = flow.getId();
}
/**
* Restore conversation scope for this flow execution.
*/
void setConversationScope(MutableAttributeMap conversationScope) {
this.conversationScope = conversationScope;
}
/**
* Restore the flow execution key.
*/
void setKey(FlowExecutionKey key) {
this.key = key;
}
/** /**
* Returns the flow definition id of this flow execution. * Returns the flow definition id of this flow execution.
*/ */
@@ -471,6 +452,27 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
return flowSessions.listIterator(1); return flowSessions.listIterator(1);
} }
/**
* Restore the flow definition of this flow execution.
*/
void setFlow(Flow flow) {
this.flow = flow;
}
/**
* Restore conversation scope for this flow execution.
*/
void setConversationScope(MutableAttributeMap conversationScope) {
this.conversationScope = conversationScope;
}
/**
* Restore the flow execution key.
*/
void setKey(FlowExecutionKey key) {
this.key = key;
}
// custom serialization (implementation of Externalizable for optimized storage) // custom serialization (implementation of Externalizable for optimized storage)
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
@@ -483,7 +485,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
out.writeBoolean(started); out.writeBoolean(started);
out.writeObject(flowId); out.writeObject(flow.getId());
out.writeObject(flowSessions); out.writeObject(flowSessions);
out.writeObject(flashScope); out.writeObject(flashScope);
out.writeObject(messagesMemento); out.writeObject(messagesMemento);
@@ -501,7 +503,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
return new ToStringCreator(this).append("flow", flow.getId()).append("flowSessions", flowSessions) return new ToStringCreator(this).append("flow", flow.getId()).append("flowSessions", flowSessions)
.append("flashScope", flashScope).toString(); .append("flashScope", flashScope).toString();
} else { } else {
return "[Unhydrated " + getCaption() + "]"; return "[Unhydrated execution of '" + flowId + "']";
} }
} }
} }
@@ -532,13 +534,14 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
private FlowExecutionException wrap(Exception e) { private FlowExecutionException wrap(Exception e) {
if (isActive()) { if (isActive()) {
FlowSessionImpl session = getActiveSessionInternal(); FlowSession session = getActiveSession();
String flowId = session.getFlowId(); String flowId = session.getDefinition().getId();
String stateId = session.getStateId(); String stateId = session.getState() != null ? session.getState().getId() : null;
return new FlowExecutionException(flowId, stateId, "Exception thrown in state '" + stateId + "' of flow '" return new FlowExecutionException(flowId, stateId, "Exception thrown in state '" + stateId + "' of flow '"
+ flowId + "'", e); + flowId + "'", e);
} else { } else {
return new FlowExecutionException(flowId, null, "Exception thrown within inactive flow '" + flowId + "'", e); return new FlowExecutionException(flow.getId(), null, "Exception thrown within inactive flow '"
+ flow.getId() + "'", e);
} }
} }

View File

@@ -51,36 +51,35 @@ public class FlowExecutionImplStateRestorer extends FlowExecutionImplServicesCon
public FlowExecution restoreState(FlowExecution flowExecution, FlowExecutionKey key, public FlowExecution restoreState(FlowExecution flowExecution, FlowExecutionKey key,
MutableAttributeMap conversationScope, FlowExecutionKeyFactory keyFactory) { MutableAttributeMap conversationScope, FlowExecutionKeyFactory keyFactory) {
FlowExecutionImpl impl = (FlowExecutionImpl) flowExecution; FlowExecutionImpl execution = (FlowExecutionImpl) flowExecution;
if (impl.getFlowId() == null) { if (execution.getFlowId() == null) {
throw new IllegalStateException("Cannot restore flow execution impl: the flow id is null"); throw new IllegalStateException("Cannot restore flow execution impl: the flow id is null");
} }
if (impl.getFlowSessions() == null) { if (execution.getFlowSessions() == null) {
throw new IllegalStateException("Cannot restore flow execution impl: the flowSessions list is null"); throw new IllegalStateException("Cannot restore flow execution impl: the flowSessions list is null");
} }
Flow flow = (Flow) definitionLocator.getFlowDefinition(impl.getFlowId()); Flow flow = (Flow) definitionLocator.getFlowDefinition(execution.getFlowId());
impl.setFlow(flow); execution.setFlow(flow);
if (impl.hasSessions()) { if (execution.hasSessions()) {
FlowSessionImpl root = impl.getRootSession(); FlowSessionImpl rootSession = execution.getRootSession();
root.setFlow(flow); rootSession.setFlow(flow);
root.setState(flow.getStateInstance(root.getStateId())); rootSession.setState(flow.getStateInstance(rootSession.getStateId()));
if (impl.hasSubflowSessions()) { if (execution.hasSubflowSessions()) {
for (ListIterator it = impl.getSubflowSessionIterator(); it.hasNext();) { for (ListIterator it = execution.getSubflowSessionIterator(); it.hasNext();) {
FlowSessionImpl subflow = (FlowSessionImpl) it.next(); FlowSessionImpl subflowSession = (FlowSessionImpl) it.next();
// TODO subflows encapsulated by top-level flow Flow definition = (Flow) definitionLocator.getFlowDefinition(subflowSession.getFlowId());
Flow definition = (Flow) definitionLocator.getFlowDefinition(subflow.getFlowId()); subflowSession.setFlow(definition);
subflow.setFlow(definition); subflowSession.setState(definition.getStateInstance(subflowSession.getStateId()));
subflow.setState(definition.getStateInstance(subflow.getStateId()));
} }
} }
} }
impl.setKey(key); execution.setKey(key);
if (conversationScope == null) { if (conversationScope == null) {
conversationScope = new LocalAttributeMap(); conversationScope = new LocalAttributeMap();
} }
impl.setConversationScope(conversationScope); execution.setConversationScope(conversationScope);
configureServices(impl); configureServices(execution);
impl.setKeyFactory(keyFactory); execution.setKeyFactory(keyFactory);
return impl; return execution;
} }
} }

View File

@@ -88,7 +88,8 @@ class FlowSessionImpl implements FlowSession, Externalizable {
* @param parent this session's parent (may be null) * @param parent this session's parent (may be null)
*/ */
public FlowSessionImpl(Flow flow, FlowSessionImpl parent) { public FlowSessionImpl(Flow flow, FlowSessionImpl parent) {
setFlow(flow); Assert.notNull(flow, "The flow is required");
this.flow = flow;
this.parent = parent; this.parent = parent;
} }
@@ -126,6 +127,18 @@ class FlowSessionImpl implements FlowSession, Externalizable {
return parent == null; return parent == null;
} }
// public impl
public void setCurrentState(State state) {
if (this.state != null && this.state.isViewState()) {
destroyViewScope();
}
this.state = state;
if (this.state.isViewState()) {
initViewScope();
}
}
// custom serialization // custom serialization
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
@@ -136,8 +149,8 @@ class FlowSessionImpl implements FlowSession, Externalizable {
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(flowId); out.writeObject(flow.getId());
out.writeObject(stateId); out.writeObject(state.getId());
out.writeObject(scope); out.writeObject(scope);
out.writeObject(parent); out.writeObject(parent);
} }
@@ -148,8 +161,7 @@ class FlowSessionImpl implements FlowSession, Externalizable {
return flow; return flow;
} }
// package private setters for setting/updating internal state // package private setters used by FlowExecutionImplStateRestorer for setting/updating internal state
// used by FlowExecutionImplStateRestorer
/** /**
* Restores the definition of this flow session. * Restores the definition of this flow session.
@@ -159,7 +171,6 @@ class FlowSessionImpl implements FlowSession, Externalizable {
void setFlow(Flow flow) { void setFlow(Flow flow) {
Assert.notNull(flow, "The flow is required"); Assert.notNull(flow, "The flow is required");
this.flow = flow; this.flow = flow;
this.flowId = flow.getId();
} }
/** /**
@@ -173,39 +184,44 @@ class FlowSessionImpl implements FlowSession, Externalizable {
Assert.isTrue(flow == state.getOwner(), Assert.isTrue(flow == state.getOwner(),
"The state does not belong to the flow associated with this flow session"); "The state does not belong to the flow associated with this flow session");
this.state = state; this.state = state;
this.stateId = state.getId();
} }
/** /**
* Returns the id of the flow of this session. * Returns the de-serialized id indicating the flow id of this session.
*/ */
String getFlowId() { String getFlowId() {
return flowId; return flowId;
} }
/** /**
* Returns the id of the current state of this session. * Returns the de-serialized id indicating the current state of this session.
*/ */
String getStateId() { String getStateId() {
return stateId; return stateId;
} }
// internal helpers
/** /**
* Initialize the view scope data structure. * Initialize the view scope data structure.
*/ */
void initViewScope() { private void initViewScope() {
scope.put(FLOW_VIEW_MAP_ATTRIBUTE, new LocalAttributeMap()); scope.put(FLOW_VIEW_MAP_ATTRIBUTE, new LocalAttributeMap());
} }
/** /**
* Destroy the view scope data structure. * Destroy the view scope data structure.
*/ */
void destroyViewScope() { private void destroyViewScope() {
scope.remove(FLOW_VIEW_MAP_ATTRIBUTE); scope.remove(FLOW_VIEW_MAP_ATTRIBUTE);
} }
public String toString() { public String toString() {
return new ToStringCreator(this).append("flow", flowId).append("state", stateId).append("scope", scope) if (flow != null) {
.toString(); return new ToStringCreator(this).append("flow", flow.getId()).append("state",
state != null ? state.getId() : null).append("scope", scope).toString();
} else {
return "[Unhydrated session '" + flowId + "' in state '" + stateId + "']";
}
} }
} }