KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > webflow > engine > State


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.webflow.engine;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.springframework.core.style.ToStringCreator;
21 import org.springframework.util.Assert;
22 import org.springframework.webflow.definition.FlowDefinition;
23 import org.springframework.webflow.definition.StateDefinition;
24 import org.springframework.webflow.execution.FlowExecutionException;
25 import org.springframework.webflow.execution.ViewSelection;
26
27 /**
28  * A point in a flow where something happens. What happens is determined by a
29  * state's type. Standard types of states include action states, view states,
30  * subflow states, and end states.
31  * <p>
32  * Each state is associated with exactly one owning flow definition.
33  * Specializations of this class capture all the configuration information
34  * needed for a specific kind of state.
35  * <p>
36  * Subclasses should implement the <code>doEnter</code> method to execute the
37  * processing that should occur when this state is entered, acting on its
38  * configuration information. The ability to plugin custom state types that
39  * execute different behaviour polymorphically is the classic GoF state pattern.
40  * <p>
41  * Equality: Two states are equal if they have the same id and are part of the same flow.
42  *
43  * @see org.springframework.webflow.engine.TransitionableState
44  * @see org.springframework.webflow.engine.ActionState
45  * @see org.springframework.webflow.engine.ViewState
46  * @see org.springframework.webflow.engine.SubflowState
47  * @see org.springframework.webflow.engine.EndState
48  * @see org.springframework.webflow.engine.DecisionState
49  *
50  * @author Keith Donald
51  * @author Erwin Vervaet
52  */

53 public abstract class State extends AnnotatedObject implements StateDefinition {
54
55     /**
56      * Logger, for use in subclasses.
57      */

58     protected final Log logger = LogFactory.getLog(getClass());
59
60     /**
61      * The state's owning flow.
62      */

63     private Flow flow;
64
65     /**
66      * The state identifier, unique to the owning flow.
67      */

68     private String JavaDoc id;
69
70     /**
71      * The list of actions to invoke when this state is entered.
72      */

73     private ActionList entryActionList = new ActionList();
74
75     /**
76      * The set of exception handlers for this state.
77      */

78     private FlowExecutionExceptionHandlerSet exceptionHandlerSet = new FlowExecutionExceptionHandlerSet();
79
80     /**
81      * Creates a state for the provided <code>flow</code> identified by the
82      * provided <code>id</code>. The id must be locally unique to the owning
83      * flow. The state will be automatically added to the flow.
84      * @param flow the owning flow
85      * @param id the state identifier (must be unique to the flow)
86      * @throws IllegalArgumentException if this state cannot be added to the
87      * flow, for instance when the provided id is not unique in the owning flow
88      * @see #getEntryActionList()
89      * @see #getExceptionHandlerSet()
90      */

91     protected State(Flow flow, String JavaDoc id) throws IllegalArgumentException JavaDoc {
92         setId(id);
93         setFlow(flow);
94     }
95
96     // implementing StateDefinition
97

98     public FlowDefinition getOwner() {
99         return flow;
100     }
101     
102     public String JavaDoc getId() {
103         return id;
104     }
105     
106     // implementation specific
107

108     /**
109      * Returns the owning flow.
110      */

111     public Flow getFlow() {
112         return flow;
113     }
114
115     /**
116      * Set the owning flow.
117      * @throws IllegalArgumentException if this state cannot be added to the
118      * flow
119      */

120     private void setFlow(Flow flow) throws IllegalArgumentException JavaDoc {
121         Assert.hasText(getId(), "The id of the state should be set before adding the state to a flow");
122         Assert.notNull(flow, "The owning flow is required");
123         this.flow = flow;
124         flow.add(this);
125     }
126
127     /**
128      * Set the state identifier, unique to the owning flow.
129      * @param id the state identifier
130      */

131     private void setId(String JavaDoc id) {
132         Assert.hasText(id, "This state must have a valid identifier");
133         this.id = id;
134     }
135
136     /**
137      * Returns the list of actions executed by this state when it is entered.
138      * The returned list is mutable.
139      * @return the state entry action list
140      */

141     public ActionList getEntryActionList() {
142         return entryActionList;
143     }
144
145     /**
146      * Returns a mutable set of exception handlers, allowing manipulation of how
147      * exceptions are handled when thrown within this state.
148      * <p>
149      * Exception handlers are invoked when an exception occurs when this state
150      * is entered, and can execute custom exception handling logic as well as
151      * select an error view to display.
152      * @return the state exception handler set
153      */

154     public FlowExecutionExceptionHandlerSet getExceptionHandlerSet() {
155         return exceptionHandlerSet;
156     }
157
158     /**
159      * Returns a flag indicating if this state is the start state of its owning
160      * flow.
161      * @return true if the flow is the start state, false otherwise
162      */

163     public boolean isStartState() {
164         return flow.getStartState() == this;
165     }
166     
167     // id and flow based equality
168

169     public boolean equals(Object JavaDoc o) {
170         if (!(o instanceof State)) {
171             return false;
172         }
173         State other = (State)o;
174         return id.equals(other.id) && flow.equals(other.flow);
175     }
176     
177     public int hashCode() {
178         return id.hashCode() + flow.hashCode();
179     }
180     
181     // behavioral methods
182

183     /**
184      * Enter this state in the provided flow control context. This
185      * implementation just calls the
186      * {@link #doEnter(RequestControlContext)} hook method, which should
187      * be implemented by subclasses, after executing the entry actions.
188      * @param context the control context for the currently executing flow, used
189      * by this state to manipulate the flow execution
190      * @return a view selection containing model and view information needed to
191      * render the results of the state processing
192      * @throws FlowExecutionException if an exception occurs in this state
193      */

194     public final ViewSelection enter(RequestControlContext context) throws FlowExecutionException {
195         if (logger.isDebugEnabled()) {
196             logger.debug("Entering state '" + getId() + "' of flow '" + getFlow().getId() + "'");
197         }
198         context.setCurrentState(this);
199         entryActionList.execute(context);
200         return doEnter(context);
201     }
202
203     /**
204      * Hook method to execute custom behaviour as a result of entering this
205      * state. By implementing this method subclasses specialize the behaviour of
206      * the state.
207      * @param context the control context for the currently executing flow, used
208      * by this state to manipulate the flow execution
209      * @return a view selection containing model and view information needed to
210      * render the results of the state processing
211      * @throws FlowExecutionException if an exception occurs in this state
212      */

213     protected abstract ViewSelection doEnter(RequestControlContext context) throws FlowExecutionException;
214
215     /**
216      * Handle an exception that occured in this state during the context of the
217      * current flow execution request.
218      * @param exception the exception that occured
219      * @param context the flow execution control context
220      * @return the selected error view, or <code>null</code> if no handler
221      * matched or returned a non-null view selection
222      */

223     public ViewSelection handleException(FlowExecutionException exception, RequestControlContext context) {
224         return getExceptionHandlerSet().handleException(exception, context);
225     }
226
227     public String JavaDoc toString() {
228         String JavaDoc flowName = (flow == null ? "<not set>" : flow.getId());
229         ToStringCreator creator = new ToStringCreator(this).append("id", getId()).append("flow", flowName).append(
230                 "entryActionList", entryActionList).append("exceptionHandlerSet", exceptionHandlerSet);
231         appendToString(creator);
232         return creator.toString();
233     }
234
235     /**
236      * Subclasses may override this hook method to stringify their internal
237      * state. This default implementation does nothing.
238      * @param creator the toString creator, to stringify properties
239      */

240     protected void appendToString(ToStringCreator creator) {
241     }
242 }
Popular Tags