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;
017:
018: import org.springframework.core.style.StylerUtils;
019: import org.springframework.core.style.ToStringCreator;
020: import org.springframework.webflow.definition.TransitionDefinition;
021: import org.springframework.webflow.definition.TransitionableStateDefinition;
022: import org.springframework.webflow.execution.RequestContext;
023: import org.springframework.webflow.execution.ViewSelection;
024:
025: /**
026: * Abstract superclass for states that can execute a transition in response to
027: * an event.
028: *
029: * @see org.springframework.webflow.engine.Transition
030: * @see org.springframework.webflow.engine.TransitionCriteria
031: *
032: * @author Keith Donald
033: * @author Erwin Vervaet
034: */
035: public abstract class TransitionableState extends State implements
036: TransitionableStateDefinition {
037:
038: /**
039: * The set of possible transitions out of this state.
040: */
041: private TransitionSet transitions = new TransitionSet();
042:
043: /**
044: * An actions to execute when exiting this state.
045: */
046: private ActionList exitActionList = new ActionList();
047:
048: /**
049: * Create a new transitionable state.
050: * @param flow the owning flow
051: * @param id the state identifier (must be unique to the flow)
052: * @throws IllegalArgumentException when this state cannot be added to given
053: * flow, for instance when the id is not unique
054: * @see State#State(Flow, String)
055: * @see #getTransitionSet()
056: */
057: protected TransitionableState(Flow flow, String id)
058: throws IllegalArgumentException {
059: super (flow, id);
060: }
061:
062: // implementing TranstionableStateDefinition
063:
064: public TransitionDefinition[] getTransitions() {
065: return getTransitionSet().toArray();
066: }
067:
068: /**
069: * Returns the set of transitions. The returned set is mutable.
070: */
071: public TransitionSet getTransitionSet() {
072: return transitions;
073: }
074:
075: /**
076: * Get a transition in this state for given flow execution request context.
077: * Throws and exception when there is no corresponding transition.
078: * @throws NoMatchingTransitionException when a matching transition cannot
079: * be found
080: */
081: public Transition getRequiredTransition(RequestContext context)
082: throws NoMatchingTransitionException {
083: Transition transition = getTransitionSet().getTransition(
084: context);
085: if (transition == null) {
086: throw new NoMatchingTransitionException(
087: getFlow().getId(),
088: getId(),
089: context.getLastEvent(),
090: "No transition found on occurence of event '"
091: + context.getLastEvent()
092: + "' in state '"
093: + getId()
094: + "' of flow '"
095: + getFlow().getId()
096: + "' -- valid transitional criteria are "
097: + StylerUtils.style(getTransitionSet()
098: .getTransitionCriterias())
099: + " -- likely programmer error, check the set of TransitionCriteria for this state");
100: }
101: return transition;
102: }
103:
104: /**
105: * Returns the list of actions executed by this state when it is exited.
106: * The returned list is mutable.
107: * @return the state exit action list
108: */
109: public ActionList getExitActionList() {
110: return exitActionList;
111: }
112:
113: // behavioral methods
114:
115: /**
116: * Inform this state definition that an event was signaled in it. The
117: * signaled event is the last event available in given request context
118: * ({@link RequestContext#getLastEvent()}).
119: * @param context the flow execution control context
120: * @return the selected view
121: * @throws NoMatchingTransitionException when a matching transition cannot
122: * be found
123: */
124: public ViewSelection onEvent(RequestControlContext context)
125: throws NoMatchingTransitionException {
126: return getRequiredTransition(context).execute(this , context);
127: }
128:
129: /**
130: * Re-enter this state. This is typically called when a transition out of
131: * this state is selected, but transition execution rolls back and as a
132: * result the flow reenters the source state.
133: * <p>
134: * By default, this just calls <code>enter()</code>.
135: * @param context the flow control context in an executing flow (a client
136: * instance of a flow)
137: * @return a view selection containing model and view information needed to
138: * render the results of the state processing
139: */
140: public ViewSelection reenter(RequestControlContext context) {
141: return enter(context);
142: }
143:
144: /**
145: * Exit this state. This is typically called when a transition takes the
146: * flow out of this state into another state. By default just executes any
147: * registered exit actions.
148: * @param context the flow control context
149: */
150: public void exit(RequestControlContext context) {
151: exitActionList.execute(context);
152: }
153:
154: protected void appendToString(ToStringCreator creator) {
155: creator.append("transitions", transitions).append(
156: "exitActionList", exitActionList);
157: }
158: }
|