001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.engine.impl;
017:
018: import java.io.Externalizable;
019: import java.io.IOException;
020: import java.io.ObjectInput;
021: import java.io.ObjectOutput;
022:
023: import org.springframework.core.style.ToStringCreator;
024: import org.springframework.util.Assert;
025: import org.springframework.webflow.core.collection.LocalAttributeMap;
026: import org.springframework.webflow.core.collection.MutableAttributeMap;
027: import org.springframework.webflow.definition.FlowDefinition;
028: import org.springframework.webflow.definition.StateDefinition;
029: import org.springframework.webflow.engine.Flow;
030: import org.springframework.webflow.engine.State;
031: import org.springframework.webflow.execution.FlowSession;
032: import org.springframework.webflow.execution.FlowSessionStatus;
033:
034: /**
035: * Implementation of the FlowSession interfaced used internally by the
036: * <code>FlowExecutionImpl</code>. This class is closely coupled with
037: * <code>FlowExecutionImpl</code> and <code>RequestControlContextImpl</code>.
038: * The three classes work together to form a complete flow execution
039: * implementation.
040: *
041: * @author Keith Donald
042: * @author Erwin Vervaet
043: * @author Ben Hale
044: */
045: class FlowSessionImpl implements FlowSession, Externalizable {
046:
047: /**
048: * The flow definition (a singleton).
049: * <p>
050: * Transient to support restoration by the
051: * {@link FlowExecutionImplStateRestorer}.
052: */
053: private transient Flow flow;
054:
055: /**
056: * Set so the transient {@link #flow} field can be restored by the
057: * {@link FlowExecutionImplStateRestorer}.
058: */
059: private String flowId;
060:
061: /**
062: * The current state of this flow session.
063: * <p>
064: * Transient to support restoration by the
065: * {@link FlowExecutionImplStateRestorer}.
066: */
067: private transient State state;
068:
069: /**
070: * Set so the transient {@link #state} field can be restored by the
071: * {@link FlowExecutionImplStateRestorer}.
072: */
073: private String stateId;
074:
075: /**
076: * The session status; may be CREATED, STARTING, ACTIVE, PAUSED, SUSPENDED,
077: * or ENDED.
078: */
079: private FlowSessionStatus status = FlowSessionStatus.CREATED;
080:
081: /**
082: * The session data model ("flow scope").
083: */
084: private MutableAttributeMap scope = new LocalAttributeMap();
085:
086: /**
087: * The flash map ("flash scope").
088: */
089: private MutableAttributeMap flashMap = new LocalAttributeMap();
090:
091: /**
092: * The parent session of this session (may be <code>null</code> if this is
093: * a root session.)
094: */
095: private FlowSessionImpl parent;
096:
097: /**
098: * Default constructor required for externalizable serialization. Should NOT
099: * be called programmatically.
100: */
101: public FlowSessionImpl() {
102: }
103:
104: /**
105: * Create a new flow session.
106: * @param flow the flow definition associated with this flow session
107: * @param parent this session's parent (may be null)
108: */
109: public FlowSessionImpl(Flow flow, FlowSessionImpl parent) {
110: setFlow(flow);
111: this .parent = parent;
112: }
113:
114: // implementing FlowSession
115:
116: public FlowDefinition getDefinition() {
117: return flow;
118: }
119:
120: public StateDefinition getState() {
121: return state;
122: }
123:
124: public FlowSessionStatus getStatus() {
125: return status;
126: }
127:
128: public MutableAttributeMap getScope() {
129: return scope;
130: }
131:
132: public MutableAttributeMap getFlashMap() {
133: return flashMap;
134: }
135:
136: public FlowSession getParent() {
137: return parent;
138: }
139:
140: public boolean isRoot() {
141: return parent == null;
142: }
143:
144: // custom serialization
145:
146: public void readExternal(ObjectInput in) throws IOException,
147: ClassNotFoundException {
148: flowId = (String) in.readObject();
149: stateId = (String) in.readObject();
150: status = (FlowSessionStatus) in.readObject();
151: scope = (MutableAttributeMap) in.readObject();
152: flashMap = (MutableAttributeMap) in.readObject();
153: parent = (FlowSessionImpl) in.readObject();
154: }
155:
156: public void writeExternal(ObjectOutput out) throws IOException {
157: out.writeObject(flowId);
158: out.writeObject(stateId);
159: out.writeObject(status);
160: out.writeObject(scope);
161: out.writeObject(flashMap);
162: out.writeObject(parent);
163: }
164:
165: // package private setters for setting/updating internal state
166: // used by FlowExecutionImplStateRestorer
167:
168: /**
169: * Restores the definition of this flow session.
170: * @param flow the flow sessions definition
171: * @see FlowExecutionImplStateRestorer
172: */
173: void setFlow(Flow flow) {
174: Assert.notNull(flow, "The flow is required");
175: this .flow = flow;
176: this .flowId = flow.getId();
177: }
178:
179: /**
180: * Set the current state of this flow session.
181: * @param state the state that is currently active in this flow session
182: * @see FlowExecutionImpl#setCurrentState(State)
183: * @see FlowExecutionImplStateRestorer
184: */
185: void setState(State state) {
186: Assert.notNull(state, "The state is required");
187: Assert
188: .isTrue(flow == state.getOwner(),
189: "The state does not belong to the flow associated with this flow session");
190: this .state = state;
191: this .stateId = state.getId();
192: }
193:
194: /**
195: * Set the status of this flow session.
196: * @param status the new status to set
197: */
198: void setStatus(FlowSessionStatus status) {
199: Assert.notNull(status, "The flow session status is requred");
200: this .status = status;
201: }
202:
203: /**
204: * Returns the id of the flow of this session.
205: */
206: String getFlowId() {
207: return flowId;
208: }
209:
210: /**
211: * Returns the id of the current state of this session.
212: */
213: String getStateId() {
214: return stateId;
215: }
216:
217: public String toString() {
218: return new ToStringCreator(this ).append("flow", flowId).append(
219: "state", stateId).append("scope", scope).append(
220: "flashMap", flashMap).append("status", status)
221: .toString();
222: }
223: }
|