⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subflowstate.java

📁 spring的WEB开发插件,支持多状态WEB开发
💻 JAVA
字号:
/*
 * Copyright 2002-2005 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 java.util.HashMap;
import java.util.Map;

import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;

/**
 * A transitionable state that spawns a subflow when executed.  When the subflow this
 * state spawns ends, the ending result is used as grounds for a state transition out
 * of this state.
 * <p>
 * A sub flow state may be configured to map input data from its flow -- acting as the
 * parent flow -- down to the subflow when the subflow is spawned.  In addition, output
 * data produced by the subflow may be mapped up to the parent flow when the subflow ends
 * and the parent flow resumes.  See the {@link FlowAttributeMapper} interface definition
 * for more information on how to do this. The logic for ending a subflow is located in the
 * {@link EndState} implementation.
 * 
 * @see org.springframework.webflow.FlowAttributeMapper
 * @see org.springframework.webflow.EndState
 * 
 * @author Keith Donald
 * @author Erwin Vervaet
 */
public class SubflowState extends TransitionableState implements FlowAttributeMapper {
	
	/**
	 * Name of the property used to indicate the start state in which
	 * to start the sub flow.
	 */
	public static final String START_STATE_PROPERTY = "startState";

	/**
	 * The subflow that should be spawned when this subflow state is entered.
	 */
	private Flow subflow;

	/**
	 * The attribute mapper that should map attributes from the parent flow down
	 * to the spawned subflow and visa versa.
	 */
	private FlowAttributeMapper attributeMapper;
	
	/**
	 * Default constructor for bean style usage.
	 */
	public SubflowState() {
	}

	/**
	 * Create a new sub flow state.
	 * @param flow the owning flow
	 * @param id the state identifier (must be unique to the flow)
	 * @param subflow the sub flow to spawn
	 * @param transition the sole transition of this state
	 * @throws IllegalArgumentException when this state cannot be added to given
	 *         flow
	 */
	public SubflowState(Flow flow, String id, Flow subflow, Transition transition) throws IllegalArgumentException {
		this(flow, id, subflow, new Transition[] { transition });
	}

	/**
	 * Create a new sub flow state.
	 * @param flow the owning flow
	 * @param id the state identifier (must be unique to the flow)
	 * @param subflow the sub flow to spawn
	 * @param transitions the transitions of this state
	 * @throws IllegalArgumentException when this state cannot be added to given
	 *         flow
	 */
	public SubflowState(Flow flow, String id, Flow subflow, Transition[] transitions) throws IllegalArgumentException {
		this(flow, id, subflow, null, transitions);
	}

	/**
	 * Create a new sub flow state.
	 * @param flow the owning flow
	 * @param id the state identifier (must be unique to the flow)
	 * @param subflow the sub flow to spawn
	 * @param transitions the transitions of this state
	 * @param properties additional properties describing this state
	 * @throws IllegalArgumentException when this state cannot be added to given
	 *         flow
	 */
	public SubflowState(Flow flow, String id, Flow subflow, Transition[] transitions, Map properties)
			throws IllegalArgumentException {
		this(flow, id, subflow, null, transitions, properties);
	}

	/**
	 * Create a new sub flow state.
	 * @param flow the owning flow
	 * @param id the state identifier (must be unique to the flow)
	 * @param subflow the sub flow to spawn
	 * @param attributeMapper the attribute mapper to use
	 * @param transition the sole transition of this state
	 * @throws IllegalArgumentException when this state cannot be added to given
	 *         flow
	 */
	public SubflowState(Flow flow, String id, Flow subflow, FlowAttributeMapper attributeMapper, Transition transition)
			throws IllegalArgumentException {
		this(flow, id, subflow, attributeMapper, new Transition[] { transition });
	}

	/**
	 * Create a new sub flow state.
	 * @param flow the owning flow
	 * @param id the state identifier (must be unique to the flow)
	 * @param subflow the sub flow to spawn
	 * @param attributeMapper the attribute mapper to use
	 * @param transitions the transitions of this state
	 * @throws IllegalArgumentException when this state cannot be added to given
	 *         flow
	 */
	public SubflowState(Flow flow, String id, Flow subflow, FlowAttributeMapper attributeMapper,
			Transition[] transitions) throws IllegalArgumentException {
		super(flow, id, transitions);
		setSubflow(subflow);
		setAttributeMapper(attributeMapper);
	}

	/**
	 * Create a new sub flow state.
	 * @param flow the owning flow
	 * @param id the state identifier (must be unique to the flow)
	 * @param subflow the sub flow to spawn
	 * @param attributeMapper the attribute mapper to use
	 * @param transitions the transitions of this state
	 * @param properties additional properties describing this state
	 * @throws IllegalArgumentException when this state cannot be added to given
	 *         flow
	 */
	public SubflowState(Flow flow, String id, Flow subflow, FlowAttributeMapper attributeMapper,
			Transition[] transitions, Map properties) throws IllegalArgumentException {
		super(flow, id, transitions, properties);
		setSubflow(subflow);
		setAttributeMapper(attributeMapper);
	}

	/**
	 * Set the sub flow that will be spawned by this state.
	 * @param subflow the sub flow to spawn
	 */
	public void setSubflow(Flow subflow) {
		Assert.notNull(subflow, "A sub flow state must have a sub flow");
		this.subflow = subflow;
	}

	/**
	 * Returns the sub flow spawned by this state.
	 */
	public Flow getSubflow() {
		return this.subflow;
	}

	/**
	 * Set the attribute mapper to use to map model data between parent and sub
	 * flow model. Can be null if no mapping is needed.
	 */
	public void setAttributeMapper(FlowAttributeMapper attributeMapper) {
		this.attributeMapper = attributeMapper;
	}

	/**
	 * Returns the attribute mapper used to map data between parent and sub flow
	 * model, or null if no mapping is needed.
	 */
	public FlowAttributeMapper getAttributeMapper() {
		return this.attributeMapper;
	}

	/**
	 * Specialization of State's <code>doEnter</code> template method that executes
	 * behaivior specific to this state type in polymorphic fashion.
	 * <p>
	 * Entering this state, creates the sub flow input map and spawns the sub
	 * flow in the current flow execution.
	 * @param context the state context for the executing flow
	 * @return a view descriptor containing model and view information needed to
	 *         render the results of the state execution
	 */
	protected ViewDescriptor doEnter(StateContext context) {
		if (logger.isDebugEnabled()) {
			logger.debug("Spawning subflow '" + getSubflow().getId() + "' within this flow '" + getFlow().getId() + "'");
		}
		return context.spawn(getSubflowStartState(context), createSubflowInput(context));
	}
	
	/**
	 * Helper method to determine the state in which the spawned subflow should
	 * start.
	 * @param context the flow execution request context
	 * @return the start state of the subflow
	 */
	protected State getSubflowStartState(RequestContext context) {
		if (containsProperty(START_STATE_PROPERTY)) {
			// use specified start state
			return getSubflow().getRequiredState((String)getProperty(START_STATE_PROPERTY));
		}
		else {
			// just use the preconfigured start state
			return getSubflow().getStartState();
		}
	}

	public Map createSubflowInput(RequestContext context) {
		if (getAttributeMapper() != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Messaging the configured attribute mapper to map attributes "
						+ "down to the spawned subflow for access within the subflow");
			}
			return this.attributeMapper.createSubflowInput(context);
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("No attribute mapper configured for this subflow state '"	+ getId()
						+ "' -- as a result, no attributes in flow scope will be passed to the spawned subflow '"
						+ subflow.getId() + "'");
			}
			return new HashMap();
		}
	}

	public void mapSubflowOutput(RequestContext context) {
		if (getAttributeMapper() != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Messaging the configured attribute mapper to map subflow attributes back up to this resuming flow -- "
						+ "I will have access to attributes passed up by the completed sub flow");
			}
			this.attributeMapper.mapSubflowOutput(context);
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("No attribute mapper is configured for the resuming state '" + getId()
						+ "' -- note: as a result, no attributes in the ending subflow scope will be passed to this resuming flow");
			}
		}
	}
	
	protected void createToString(ToStringCreator creator) {
		creator.append("subflow", subflow.getId()).append("attributeMapper", attributeMapper);
		super.createToString(creator);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -