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.support;
017:
018: import java.io.Serializable;
019:
020: import org.springframework.binding.expression.Expression;
021: import org.springframework.binding.expression.ExpressionParser;
022: import org.springframework.binding.expression.SettableExpression;
023: import org.springframework.binding.mapping.AttributeMapper;
024: import org.springframework.binding.mapping.DefaultAttributeMapper;
025: import org.springframework.binding.mapping.Mapping;
026: import org.springframework.core.style.ToStringCreator;
027: import org.springframework.util.Assert;
028: import org.springframework.webflow.core.DefaultExpressionParserFactory;
029: import org.springframework.webflow.execution.ScopeType;
030:
031: /**
032: * Generic flow attribute mapper implementation that allows mappings to be
033: * configured in a declarative fashion.
034: * <p>
035: * Two types of mappings may be configured, input mappings and output mappings:
036: * <ol>
037: * <li>Input mappings define the rules for mapping attributes in a parent flow
038: * to a spawning subflow.
039: * <li>Output mappings define the rules for mapping attributes returned from an
040: * ended subflow into the resuming parent.
041: * </ol>
042: * <p>
043: * The mappings defined using the configuration properties fully support bean
044: * property access. So an entry name in a mapping can either be "beanName" or
045: * "beanName.propName". Nested property values are also supported
046: * ("beanName.propName.nestedPropName"). When the <i>from</i> mapping string is
047: * enclosed in "${...}", it will be interpreted as an expression that will be
048: * evaluated against the flow execution request context.
049: *
050: * @see org.springframework.webflow.execution.RequestContext
051: *
052: * @author Erwin Vervaet
053: * @author Keith Donald
054: * @author Colin Sampaleanu
055: */
056: public class ConfigurableFlowAttributeMapper extends
057: AbstractFlowAttributeMapper implements Serializable {
058:
059: /*
060: * Note: no longer used by the Spring Web Flow code base. Kept around
061: * for possible usage by end users.
062: */
063:
064: /**
065: * The expression parser that will parse input and output attribute
066: * expressions.
067: */
068: private ExpressionParser expressionParser = DefaultExpressionParserFactory
069: .getExpressionParser();
070:
071: /**
072: * The mapper that maps attributes into a spawning subflow.
073: */
074: private DefaultAttributeMapper inputMapper = new DefaultAttributeMapper();
075:
076: /**
077: * The mapper that maps attributes returned by an ended subflow.
078: */
079: private DefaultAttributeMapper outputMapper = new DefaultAttributeMapper();
080:
081: /**
082: * Set the expression parser responsible for parsing expression strings into
083: * evaluatable expression objects.
084: */
085: public void setExpressionParser(ExpressionParser expressionParser) {
086: Assert.notNull(expressionParser,
087: "The expression parser is required");
088: this .expressionParser = expressionParser;
089: }
090:
091: /**
092: * Adds a new input mapping. Use when you need full control over defining
093: * how a subflow input attribute mapping will be perfomed.
094: * @param inputMapping the input mapping
095: * @return this, to support call chaining
096: */
097: public ConfigurableFlowAttributeMapper addInputMapping(
098: AttributeMapper inputMapping) {
099: inputMapper.addMapping(inputMapping);
100: return this ;
101: }
102:
103: /**
104: * Adds a collection of input mappings. Use when you need full control over
105: * defining how a subflow input attribute mapping will be perfomed.
106: * @param inputMappings the input mappings
107: */
108: public void addInputMappings(AttributeMapper[] inputMappings) {
109: inputMapper.addMappings(inputMappings);
110: }
111:
112: /**
113: * Adds a new output mapping. Use when you need full control over defining
114: * how a subflow output attribute mapping will be perfomed.
115: * @param outputMapping the output mapping
116: * @return this, to support call chaining
117: */
118: public ConfigurableFlowAttributeMapper addOutputMapping(
119: AttributeMapper outputMapping) {
120: outputMapper.addMapping(outputMapping);
121: return this ;
122: }
123:
124: /**
125: * Adds a collection of output mappings. Use when you need full control over
126: * defining how a subflow output attribute mapping will be perfomed.
127: * @param outputMappings the output mappings
128: */
129: public void addOutputMappings(AttributeMapper[] outputMappings) {
130: outputMapper.addMappings(outputMappings);
131: }
132:
133: /**
134: * Adds an input mapping that maps a single attribute in parent <i>flow
135: * scope</i> into the subflow input map. For instance: "x" will result in
136: * the "x" attribute in parent flow scope being mapped into the subflow
137: * input map as "x".
138: * @param attributeName the attribute in flow scope to map into the subflow
139: * @return this, to support call chaining
140: */
141: public ConfigurableFlowAttributeMapper addInputAttribute(
142: String attributeName) {
143: SettableExpression attribute = expressionParser
144: .parseSettableExpression(attributeName);
145: Expression scope = new AttributeExpression(attribute,
146: ScopeType.FLOW);
147: addInputMapping(new Mapping(scope, attribute, null));
148: return this ;
149: }
150:
151: /**
152: * Adds a collection of input mappings that map attributes in parent <i>flow
153: * scope</i> into the subflow input map. For instance: "x" will result in
154: * the "x" attribute in parent flow scope being mapped into the subflow
155: * input map as "x".
156: * @param attributeNames the attributes in flow scope to map into the
157: * subflow
158: */
159: public void addInputAttributes(String[] attributeNames) {
160: if (attributeNames == null) {
161: return;
162: }
163: for (int i = 0; i < attributeNames.length; i++) {
164: addInputAttribute(attributeNames[i]);
165: }
166: }
167:
168: /**
169: * Adds an output mapping that maps a single subflow output attribute into
170: * the <i>flow scope</i> of the resuming parent flow. For instance: "y"
171: * will result in the "y" attribute of the subflow output map being mapped
172: * into the flowscope of the resuming parent flow as "y".
173: * @param attributeName the subflow output attribute to map into the parent
174: * flow scope
175: * @return this, to support call chaining
176: */
177: public ConfigurableFlowAttributeMapper addOutputAttribute(
178: String attributeName) {
179: Expression attribute = expressionParser
180: .parseExpression(attributeName);
181: SettableExpression scope = new AttributeExpression(attribute,
182: ScopeType.FLOW);
183: addOutputMapping(new Mapping(attribute, scope, null));
184: return this ;
185: }
186:
187: /**
188: * Adds a collection of output mappings that map subflow output attributes
189: * into the scope of the resuming parent flow. For instance: "y" will result
190: * in the "y" attribute of the subflow output map being mapped into the
191: * flowscope of the resuming parent flow as "y".
192: * @param attributeNames the subflow output attributes to map into the
193: * parent flow
194: */
195: public void addOutputAttributes(String[] attributeNames) {
196: if (attributeNames == null) {
197: return;
198: }
199: for (int i = 0; i < attributeNames.length; i++) {
200: addOutputAttribute(attributeNames[i]);
201: }
202: }
203:
204: /**
205: * Returns a typed-array of configured input mappings.
206: * @return the configured input mappings
207: */
208: public AttributeMapper[] getInputMappings() {
209: return inputMapper.getMappings();
210: }
211:
212: /**
213: * Returns a typed-array of configured output mappings.
214: * @return the configured output mappings
215: */
216: public AttributeMapper[] getOutputMappings() {
217: return outputMapper.getMappings();
218: }
219:
220: /**
221: * Returns the configured expression parser. Can be used by subclasses that
222: * build mappings.
223: */
224: protected ExpressionParser getExpressionParser() {
225: return expressionParser;
226: }
227:
228: protected AttributeMapper getInputMapper() {
229: return inputMapper;
230: }
231:
232: protected AttributeMapper getOutputMapper() {
233: return outputMapper;
234: }
235:
236: public String toString() {
237: return new ToStringCreator(this ).append("inputMapper",
238: inputMapper).append("outputMapper", outputMapper)
239: .toString();
240: }
241: }
|