All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.webflow.Transition Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
/*
 * Copyright 2002-2006 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.webflow;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;

/**
 * A path from one {@link TransitionableState state} to another
 * {@link State state}.
 * 

* When executed a transition takes a flow execution from its current state, * called the source state, to another state, called the target * state. A transition may become eligible for execution on the occurence * of {@link Event} from within a transitionable source state. *

* When an event occurs within this transition's source * TransitionableState the determination of the eligibility of * this transition is made by a TransitionCriteria object called * the matching criteria. If the matching criteria returns * true this transition is marked eligible for execution for that * event. *

* Determination as to whether an eligible transition should be allowed to * execute is made by a TransitionCriteria object called the * execution criteria. If the execution criteria test fails this * transition will roll back and reenter its source state. If the * execution criteria test succeeds this transition will execute and take the * flow to the transition's target state. *

* The target state of this transition is typically specified at configuration * time using the target state id. If the target state of this transition needs * to be calculated in a dynamic fashion at runtime, set a custom * {@link TargetStateResolver} * * @see TransitionableState * @see TransitionCriteria * @see TargetStateResolver * * @author Keith Donald * @author Erwin Vervaet */ public class Transition extends AnnotatedObject { /** * Logger, for use in subclasses. */ protected final Log logger = LogFactory.getLog(Transition.class); /** * The criteria that determine whether or not this transition matches as * eligible for execution when an event occurs in the sourceState. */ private TransitionCriteria matchingCriteria = WildcardTransitionCriteria.INSTANCE; /** * The criteria that determine whether or not this transition, once matched, * should complete execution or should roll back. */ private TransitionCriteria executionCriteria = WildcardTransitionCriteria.INSTANCE; /** * The resolver responsible for calculating the target state of this * transition. */ private TargetStateResolver targetStateResolver; /** * Create a new transition that always matches and always executes, * transitioning to the target state calculated by the provided * targetStateResolver. * @param targetStateResolver the resolver of the target state of this * transition * @see #setMatchingCriteria(TransitionCriteria) * @see #setExecutionCriteria(TransitionCriteria) */ public Transition(TargetStateResolver targetStateResolver) { setTargetStateResolver(targetStateResolver); } /** * Create a new transition that matches on the specified criteria, * transitioning to the target state calculated by the provided * targetStateResolver. * @param matchingCriteria the criteria that matches this transition * @param targetStateResolver the resolver of the target state of this * transition * @see #setExecutionCriteria(TransitionCriteria) */ public Transition(TransitionCriteria matchingCriteria, TargetStateResolver targetStateResolver) { setMatchingCriteria(matchingCriteria); setTargetStateResolver(targetStateResolver); } /** * Returns the criteria that determine whether or not this transition * matches as eligible for execution. * @return the transition matching criteria */ public TransitionCriteria getMatchingCriteria() { return matchingCriteria; } /** * Set the criteria that determine whether or not this transition matches as * eligible for execution. * @param matchingCriteria the transition matching criteria */ public void setMatchingCriteria(TransitionCriteria matchingCriteria) { Assert.notNull(matchingCriteria, "The matching criteria is required"); this.matchingCriteria = matchingCriteria; } /** * Returns the criteria that determine whether or not this transition, once * matched, should complete execution or should roll back. * @return the transition execution criteria */ public TransitionCriteria getExecutionCriteria() { return executionCriteria; } /** * Set the criteria that determine whether or not this transition, once * matched, should complete execution or should roll back. * @param executionCriteria the transition execution criteria */ public void setExecutionCriteria(TransitionCriteria executionCriteria) { this.executionCriteria = executionCriteria; } /** * Returns this transition's target state resolver. */ public TargetStateResolver getTargetStateResolver() { return targetStateResolver; } /** * Set this transition's target state resolver, to calculate what state to * transition to when this transition is executed. * @param targetStateResolver the target state resolver */ public void setTargetStateResolver(TargetStateResolver targetStateResolver) { Assert.notNull(targetStateResolver, "The target state resolver is required"); this.targetStateResolver = targetStateResolver; } /** * Checks if this transition is elligible for execution given the state of * the provided flow execution request context. * @param context the flow execution request context * @return true if this transition should execute, false otherwise */ public boolean matches(RequestContext context) { return getMatchingCriteria().test(context); } /** * Checks if this transition can complete its execution or should be rolled * back, given the state of the flow execution request context. * @param context the flow execution request context * @return true if this transition can complete execution, false if it * should roll back */ public boolean canExecute(RequestContext context) { return getExecutionCriteria() != null ? getExecutionCriteria().test(context) : true; } /** * Returns the target state of this transition, possibly taking the request * context into account. * @param context the flow execution request context */ protected State getTargetState(TransitionableState sourceState, RequestContext context) { return getTargetStateResolver().resolveTargetState(this, sourceState, context); } /** * Execute this state transition. Will only be called if the * {@link #matches(RequestContext)} method returns true for given context. * @param context the flow execution control context * @return a view selection containing model and view information needed to * render the results of the transition execution * @throws FlowExecutionException when transition execution fails */ public ViewSelection execute(TransitionableState sourceState, RequestControlContext context) throws FlowExecutionException { ViewSelection selectedView; if (canExecute(context)) { if (sourceState != null) { if (logger.isDebugEnabled()) { logger.debug("Executing " + this + " out of state '" + sourceState.getId() + "'"); } sourceState.exit(context); } else { if (logger.isDebugEnabled()) { logger.debug("Executing " + this); } } State targetState = getTargetState(sourceState, context); context.setLastTransition(this); // enter the target state (note: any exceptions are propagated) selectedView = targetState.enter(context); } else { // 'roll back' and re-enter the source state if (sourceState != null) { selectedView = sourceState.reenter(context); } else { throw new IllegalStateException("Execution of '" + this + "' was blocked by '" + getExecutionCriteria() + "', " + "; however, no source state is set at runtime. " + "This is an illegal situation: check your flow definition."); } } if (logger.isDebugEnabled()) { if (context.getFlowExecutionContext().isActive()) { logger.debug("Completed execution of " + this + ", as a result the new state is '" + context.getCurrentState().getId() + "' in flow '" + context.getActiveFlow().getId() + "'"); } else { logger.debug("Completed execution of " + this + ", as a result the flow execution has ended"); } } return selectedView; } public String toString() { return new ToStringCreator(this).append("matchingCriteria", getMatchingCriteria()).append("executionCriteria", getExecutionCriteria()).append("targetStateResolver", getTargetStateResolver()).append("attributes", getAttributeMap()).toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy