001: /*
002: * Created on Nov 15, 2005
003: */
004: package uk.org.ponder.rsf.preservation;
005:
006: import java.util.ArrayList;
007: import java.util.List;
008:
009: import uk.org.ponder.beanutil.BeanLocator;
010: import uk.org.ponder.beanutil.WriteableBeanLocator;
011: import uk.org.ponder.beanutil.support.NullBeanLocator;
012: import uk.org.ponder.stringutil.StringList;
013:
014: /** The central manager of all PreservationStrategies. This is a request-scope
015: * bean which is called directly by the ActionHandler in order to be notified
016: * of life-cycle events that require preservation, restoration and destruction
017: * of the bean state stored by the Strategies.
018: * <p>This SPM implementation is specifically aware of "flow" scope state
019: * as a first-class concept. It maintains three separate
020: * pools of strategies, guided by their relationship to the flow lifecycle.
021: * Plain "strategies" are used for storage during the main lifetime of a flow.
022: * "startStrategies" are invoked not only during a flow, but at the initial
023: * launching of a flow as well, to persist any required launch state (in
024: * current RSF, this is a single bean, the FlowIDHolder). Finally, at the
025: * expiration of a flow, the "endStrategies" operate to save any (presumably
026: * reduced) state required to correctly render an "end of flow", "confirmation"
027: * style page, stored into "bandgap" state with probably short lifetime.
028: * @author Antranig Basman (amb26@ponder.org.uk)
029: *
030: */
031:
032: public class StatePreservationManager {
033: private List strategies;
034: private List startflowstrategies;
035: private List endflowstrategies;
036: private List scopestrategies;
037:
038: public void setStrategies(List strategies) {
039: this .strategies = strategies;
040: }
041:
042: public void setStartFlowStrategies(List startflowstrategies) {
043: this .startflowstrategies = startflowstrategies;
044: }
045:
046: public void setEndFlowStrategies(List endflowstrategies) {
047: this .endflowstrategies = endflowstrategies;
048: }
049:
050: public void setScopeStrategies(List scopestrategies) {
051: this .scopestrategies = scopestrategies;
052: }
053:
054: private WriteableBeanLocator wbl;
055: private BeanLocator deadbl;
056: private StringList scopelocks = new StringList();
057:
058: public void setWriteableBeanLocator(WriteableBeanLocator wbl) {
059: this .wbl = wbl;
060: }
061:
062: public void setDeadBeanLocator(BeanLocator deadbl) {
063: this .deadbl = deadbl;
064: }
065:
066: private StatePreservationStrategy strategyAt(int i) {
067: return (StatePreservationStrategy) strategies.get(i);
068: }
069:
070: private StatePreservationStrategy startStrategyAt(int i) {
071: return (StatePreservationStrategy) startflowstrategies.get(i);
072: }
073:
074: private StatePreservationStrategy endStrategyAt(int i) {
075: return (StatePreservationStrategy) endflowstrategies.get(i);
076: }
077:
078: private AutonomousStatePreservationStrategy scopeStrategyAt(int i) {
079: return (AutonomousStatePreservationStrategy) scopestrategies
080: .get(i);
081: }
082:
083: public StringList getScopeLocks() {
084: return scopelocks;
085: }
086:
087: public void init() {
088: if (strategies == null) {
089: strategies = new ArrayList(0);
090: }
091: if (endflowstrategies == null) {
092: endflowstrategies = new ArrayList(0);
093: }
094: }
095:
096: public void scopePreserve() {
097: for (int i = 0; i < scopestrategies.size(); ++i) {
098: scopeStrategyAt(i).preserve(deadbl);
099: }
100: }
101:
102: // TODO: We must make sure that expired flow can be reliably detected by
103: // storing a special subtoken on preserve, and throwing ExpiredFlowException when
104: // we fail to get it out again.
105: public void preserve(String tokenid, boolean flowstart) {
106:
107: for (int i = 0; i < strategies.size(); ++i) {
108: strategyAt(i).preserve(
109: flowstart ? NullBeanLocator.instance : deadbl,
110: tokenid);
111: }
112: for (int i = 0; i < startflowstrategies.size(); ++i) {
113: startStrategyAt(i).preserve(deadbl, tokenid);
114: }
115: }
116:
117: public void scopeRestore() {
118: for (int i = 0; i < scopestrategies.size(); ++i) {
119: StringList returned = scopeStrategyAt(i).restore(wbl);
120: if (returned != null) {
121: scopelocks.addAll(returned);
122: }
123: }
124: }
125:
126: /** Request all registered strategies to restore state into the current
127: * request-scope container.
128: * @param tokenid The flow token keying the state to be restored.
129: * @param flowend <code>true</code> if the specified flow has expired.
130: */
131: public void restore(String tokenid, boolean flowend) {
132: if (flowend) {
133: for (int i = 0; i < endflowstrategies.size(); ++i) {
134: endStrategyAt(i).restore(wbl, tokenid);
135: }
136: } else {
137: for (int i = 0; i < strategies.size(); ++i) {
138: strategyAt(i).restore(wbl, tokenid);
139: }
140: for (int i = 0; i < startflowstrategies.size(); ++i) {
141: startStrategyAt(i).restore(wbl, tokenid);
142: }
143: }
144: }
145:
146: /**
147: * Signal that the current flow (multi-request sequence) has ended. Remove all
148: * state from flow preservation strategies, and transfer to flow-end
149: * strategies (if any).
150: */
151: public void flowEnd(String tokenid) {
152: for (int i = 0; i < strategies.size(); ++i) {
153: strategyAt(i).clear(tokenid);
154: }
155: for (int i = 0; i < startflowstrategies.size(); ++i) {
156: startStrategyAt(i).clear(tokenid);
157: }
158: for (int i = 0; i < endflowstrategies.size(); ++i) {
159: endStrategyAt(i).preserve(deadbl, tokenid);
160: }
161:
162: }
163:
164: }
|