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.builder;
017:
018: import org.springframework.beans.BeansException;
019: import org.springframework.beans.factory.BeanFactory;
020: import org.springframework.binding.convert.ConversionService;
021: import org.springframework.binding.convert.support.CompositeConversionService;
022: import org.springframework.binding.convert.support.DefaultConversionService;
023: import org.springframework.binding.convert.support.GenericConversionService;
024: import org.springframework.binding.convert.support.TextToExpression;
025: import org.springframework.binding.expression.ExpressionParser;
026: import org.springframework.binding.method.TextToMethodSignature;
027: import org.springframework.core.io.DefaultResourceLoader;
028: import org.springframework.core.io.ResourceLoader;
029: import org.springframework.util.Assert;
030: import org.springframework.webflow.action.BeanInvokingActionFactory;
031: import org.springframework.webflow.core.DefaultExpressionParserFactory;
032: import org.springframework.webflow.engine.Flow;
033: import org.springframework.webflow.engine.FlowAttributeMapper;
034: import org.springframework.webflow.engine.FlowExecutionExceptionHandler;
035: import org.springframework.webflow.engine.State;
036: import org.springframework.webflow.engine.TargetStateResolver;
037: import org.springframework.webflow.engine.TransitionCriteria;
038: import org.springframework.webflow.engine.ViewSelector;
039: import org.springframework.webflow.execution.Action;
040:
041: /**
042: * Base implementation that implements a minimal set of the
043: * <code>FlowServiceLocator</code> interface, throwing unsupported operation
044: * exceptions for some operations.
045: * <p>
046: * May be subclassed to offer additional factory/lookup support.
047: *
048: * @author Keith Donald
049: */
050: public class BaseFlowServiceLocator implements FlowServiceLocator {
051:
052: /**
053: * The factory encapsulating the creation of central Flow artifacts such as
054: * {@link Flow flows} and {@link State states}.
055: */
056: private FlowArtifactFactory flowArtifactFactory = new FlowArtifactFactory();
057:
058: /**
059: * The factory encapsulating the creation of bean invoking actions, actions
060: * that adapt methods on objects to the {@link Action} interface.
061: */
062: private BeanInvokingActionFactory beanInvokingActionFactory = new BeanInvokingActionFactory();
063:
064: /**
065: * The parser for parsing expression strings into evaluatable expression
066: * objects.
067: */
068: private ExpressionParser expressionParser = DefaultExpressionParserFactory
069: .getExpressionParser();
070:
071: /**
072: * The conversion service configured by the user (none by default).
073: */
074: private ConversionService userConversionService = null;
075:
076: /**
077: * A conversion service that can convert between types.
078: */
079: private ConversionService conversionService = createConversionService(userConversionService);
080:
081: /**
082: * A resource loader that can load resources.
083: */
084: private ResourceLoader resourceLoader = new DefaultResourceLoader();
085:
086: /**
087: * Sets the factory encapsulating the creation of central Flow artifacts
088: * such as {@link Flow flows} and {@link State states}.
089: */
090: public void setFlowArtifactFactory(
091: FlowArtifactFactory flowArtifactFactory) {
092: Assert.notNull(flowArtifactFactory,
093: "The flow artifact factory is required");
094: this .flowArtifactFactory = flowArtifactFactory;
095: }
096:
097: /**
098: * Sets the factory for creating bean invoking actions, actions that adapt
099: * methods on objects to the {@link Action} interface.
100: */
101: public void setBeanInvokingActionFactory(
102: BeanInvokingActionFactory beanInvokingActionFactory) {
103: Assert.notNull(beanInvokingActionFactory,
104: "The bean invoking action factory is required");
105: this .beanInvokingActionFactory = beanInvokingActionFactory;
106: }
107:
108: /**
109: * Set the expression parser responsible for parsing expression strings into
110: * evaluatable expression objects.
111: */
112: public void setExpressionParser(ExpressionParser expressionParser) {
113: Assert.notNull(expressionParser,
114: "The expression parser is required");
115: this .expressionParser = expressionParser;
116: //this has impact on the TextToExpression converter in the conversion service!
117: this .conversionService = createConversionService(userConversionService);
118: }
119:
120: /**
121: * Set the conversion service to use to convert between types; typically
122: * from string to a rich object type.
123: */
124: public void setConversionService(
125: ConversionService userConversionService) {
126: Assert.notNull(userConversionService,
127: "The conversion service is required");
128: this .userConversionService = userConversionService;
129: this .conversionService = createConversionService(userConversionService);
130: }
131:
132: /**
133: * Set the resource loader to load file-based resources from string-encoded
134: * paths. This is optional.
135: */
136: public void setResourceLoader(ResourceLoader resourceLoader) {
137: this .resourceLoader = resourceLoader;
138: }
139:
140: public Flow getSubflow(String id)
141: throws FlowArtifactLookupException {
142: throw new FlowArtifactLookupException(id, Flow.class,
143: "Subflow lookup is not supported by this service locator");
144: }
145:
146: public Action getAction(String id)
147: throws FlowArtifactLookupException {
148: return (Action) getBean(id, Action.class);
149: }
150:
151: public FlowAttributeMapper getAttributeMapper(String id)
152: throws FlowArtifactLookupException {
153: return (FlowAttributeMapper) getBean(id,
154: FlowAttributeMapper.class);
155: }
156:
157: public TransitionCriteria getTransitionCriteria(String id)
158: throws FlowArtifactLookupException {
159: return (TransitionCriteria) getBean(id,
160: TransitionCriteria.class);
161: }
162:
163: public TargetStateResolver getTargetStateResolver(String id)
164: throws FlowArtifactLookupException {
165: return (TargetStateResolver) getBean(id,
166: TargetStateResolver.class);
167: }
168:
169: public ViewSelector getViewSelector(String id)
170: throws FlowArtifactLookupException {
171: return (ViewSelector) getBean(id, ViewSelector.class);
172: }
173:
174: public FlowExecutionExceptionHandler getExceptionHandler(String id)
175: throws FlowArtifactLookupException {
176: return (FlowExecutionExceptionHandler) getBean(id,
177: FlowExecutionExceptionHandler.class);
178: }
179:
180: public FlowArtifactFactory getFlowArtifactFactory() {
181: return flowArtifactFactory;
182: }
183:
184: public BeanInvokingActionFactory getBeanInvokingActionFactory() {
185: return beanInvokingActionFactory;
186: }
187:
188: public BeanFactory getBeanFactory()
189: throws UnsupportedOperationException {
190: throw new UnsupportedOperationException(
191: "Bean factory lookup is not supported by this service locator");
192: }
193:
194: public ResourceLoader getResourceLoader() {
195: return resourceLoader;
196: }
197:
198: public ExpressionParser getExpressionParser() {
199: return expressionParser;
200: }
201:
202: public ConversionService getConversionService() {
203: return conversionService;
204: }
205:
206: // helpers for use by subclasses
207:
208: /**
209: * Helper method for determining if the configured bean factory contains the
210: * provided bean.
211: * @param id the id of the bean
212: * @return true if yes, false otherwise
213: */
214: protected boolean containsBean(String id) {
215: return getBeanFactory().containsBean(id);
216: }
217:
218: /**
219: * Helper method to lookup the bean representing a flow artifact of the
220: * specified type.
221: * @param id the bean id
222: * @param artifactType the bean type
223: * @return the bean
224: * @throws FlowArtifactLookupException an exception occurred
225: */
226: protected Object getBean(String id, Class artifactType)
227: throws FlowArtifactLookupException {
228: try {
229: return getBeanFactory().getBean(id, artifactType);
230: } catch (BeansException e) {
231: throw new FlowArtifactLookupException(id, artifactType, e);
232: }
233: }
234:
235: /**
236: * Helper method to lookup the type of the bean with the provided id.
237: * @param id the bean id
238: * @param artifactType the bean type
239: * @return the bean's type
240: * @throws FlowArtifactLookupException an exception occurred
241: */
242: protected Class getBeanType(String id, Class artifactType)
243: throws FlowArtifactLookupException {
244: try {
245: return getBeanFactory().getType(id);
246: } catch (BeansException e) {
247: throw new FlowArtifactLookupException(id, artifactType, e);
248: }
249: }
250:
251: /**
252: * Setup a conversion service used by this flow service locator.
253: * @param userConversionService a user supplied conversion service, optional
254: * @return the newly created conversion service
255: */
256: protected ConversionService createConversionService(
257: ConversionService userConversionService) {
258: DefaultConversionService defaultConversionService = new DefaultConversionService();
259: addWebFlowConverters(defaultConversionService);
260: if (userConversionService != null) {
261: return new CompositeConversionService(
262: new ConversionService[] { userConversionService,
263: defaultConversionService });
264: } else {
265: return defaultConversionService;
266: }
267: }
268:
269: /**
270: * Add all web flow specific converters to given conversion service.
271: */
272: protected void addWebFlowConverters(
273: GenericConversionService conversionService) {
274: conversionService.addConverter(new TextToTransitionCriteria(
275: this ));
276: conversionService.addConverter(new TextToTargetStateResolver(
277: this ));
278: conversionService.addConverter(new TextToViewSelector(this ));
279: conversionService.addConverter(new TextToExpression(
280: getExpressionParser()));
281: conversionService.addConverter(new TextToMethodSignature(
282: conversionService));
283: }
284: }
|