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.executor.jsf;
017:
018: import javax.faces.context.FacesContext;
019:
020: import org.springframework.context.ApplicationContext;
021: import org.springframework.web.jsf.FacesContextUtils;
022: import org.springframework.webflow.conversation.impl.SessionBindingConversationManager;
023: import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
024: import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
025: import org.springframework.webflow.engine.impl.FlowExecutionImplStateRestorer;
026: import org.springframework.webflow.execution.FlowExecutionFactory;
027: import org.springframework.webflow.execution.repository.FlowExecutionRepository;
028: import org.springframework.webflow.execution.repository.support.SimpleFlowExecutionRepository;
029: import org.springframework.webflow.executor.FlowExecutorImpl;
030:
031: /**
032: * Trivial helper utility class for SWF within a JSF environment. Used mainly to
033: * locate Web Flow services needed to run the JSF integration.
034: *
035: * @author Keith Donald
036: */
037: public class FlowFacesUtils {
038:
039: /**
040: * Bean name of a custom flow executor implementation.
041: *
042: * Note the flow executor object is used only at configuration time to
043: * extract other lower-level services needed by the JSF integration (flow
044: * execution repository, flow execution factory). The runtime FlowExecutor
045: * interface is never used by this JSF integration.
046: */
047: private static final String FLOW_EXECUTOR_BEAN_NAME = "flowExecutor";
048:
049: /**
050: * Bean name of a custom flow execution repository implementation.
051: */
052: private static final String FLOW_EXECUTION_REPOSITORY_BEAN_NAME = "flowExecutionRepository";
053:
054: /**
055: * Bean name of a custom flow definition locator implementation.
056: */
057: private static final String FLOW_DEFINITION_LOCATOR_BEAN_NAME = "flowDefinitionLocator";
058:
059: /**
060: * Bean name of a custom flow execution factory implementation.
061: */
062: private static final String FLOW_EXECUTION_FACTORY_BEAN_NAME = "flowExecutionFactory";
063:
064: /**
065: * The default flow execution repository implementation to use.
066: */
067: private static FlowExecutionRepository defaultExecutionRepository;
068:
069: /**
070: * The default flow execution factory implementation to use.
071: */
072: private static FlowExecutionFactory defaultExecutionFactory;
073:
074: /**
075: * Returns the locator for flow definitions to use in a JSF environment.
076: * Searches for a bean in the root web application context named
077: * {@link #FLOW_DEFINITION_LOCATOR_BEAN_NAME}. A bean of type
078: * {@link FlowDefinitionLocator} must exist by this name.
079: * @param context the faces context
080: * @return the flow definition locator
081: */
082: public static FlowDefinitionLocator getDefinitionLocator(
083: FacesContext context) {
084: ApplicationContext ac = FacesContextUtils
085: .getRequiredWebApplicationContext(context);
086: if (ac.containsBean(FLOW_DEFINITION_LOCATOR_BEAN_NAME)) {
087: return (FlowDefinitionLocator) ac.getBean(
088: FLOW_DEFINITION_LOCATOR_BEAN_NAME,
089: FlowDefinitionLocator.class);
090: } else {
091: FlowExecutorImpl flowExecutor = getFlowExecutor(context);
092: if (flowExecutor != null) {
093: return flowExecutor.getDefinitionLocator();
094: } else {
095: String message = "No bean definition with id '"
096: + FLOW_DEFINITION_LOCATOR_BEAN_NAME
097: + "' or '"
098: + FLOW_EXECUTOR_BEAN_NAME
099: + "' could be found; to use Spring Web Flow with JSF a FlowDefinitionLocator must be resolvable";
100: throw new JsfFlowConfigurationException(message);
101: }
102: }
103: }
104:
105: /**
106: * Returns the flow execution repository to use in a JSF environment.
107: * Searches for a bean in the root web application context named
108: * {@link #FLOW_EXECUTION_REPOSITORY_BEAN_NAME}. If no such bean exists
109: * with this name, falls back on the repository configured by a bean with
110: * name {@link #FLOW_EXECUTOR_BEAN_NAME}. If no bean exists with that name,
111: * uses the default 'simple' repository implementation.
112: * @param context the faces context
113: * @return the flow execution repository
114: */
115: public synchronized static FlowExecutionRepository getExecutionRepository(
116: FacesContext context) {
117: ApplicationContext ac = FacesContextUtils
118: .getRequiredWebApplicationContext(context);
119: if (ac.containsBean(FLOW_EXECUTION_REPOSITORY_BEAN_NAME)) {
120: return (FlowExecutionRepository) ac.getBean(
121: FLOW_EXECUTION_REPOSITORY_BEAN_NAME,
122: FlowExecutionRepository.class);
123: } else {
124: if (defaultExecutionRepository == null) {
125: FlowExecutorImpl flowExecutor = getFlowExecutor(context);
126: if (flowExecutor != null) {
127: defaultExecutionRepository = flowExecutor
128: .getExecutionRepository();
129: } else {
130: defaultExecutionRepository = new SimpleFlowExecutionRepository(
131: new FlowExecutionImplStateRestorer(
132: getDefinitionLocator(context)),
133: new SessionBindingConversationManager());
134: }
135: }
136: return defaultExecutionRepository;
137: }
138: }
139:
140: /**
141: * Returns the flow execution factory to use in a JSF environment. Searches
142: * for a bean in the root web application context named
143: * {@link #FLOW_EXECUTION_FACTORY_BEAN_NAME}. If no such bean exists with
144: * this name, falls back on the repository configured by a bean with name
145: * {@link #FLOW_EXECUTOR_BEAN_NAME}. If no bean exists with that name, uses
146: * the default factory implementation.
147: * @param context the faces context
148: * @return the flow execution factory
149: */
150: public synchronized static FlowExecutionFactory getExecutionFactory(
151: FacesContext context) {
152: ApplicationContext ac = FacesContextUtils
153: .getRequiredWebApplicationContext(context);
154: if (ac.containsBean(FLOW_EXECUTION_FACTORY_BEAN_NAME)) {
155: return (FlowExecutionFactory) ac.getBean(
156: FLOW_EXECUTION_FACTORY_BEAN_NAME,
157: FlowExecutionFactory.class);
158: } else {
159: if (defaultExecutionFactory == null) {
160: FlowExecutorImpl flowExecutor = getFlowExecutor(context);
161: if (flowExecutor != null) {
162: defaultExecutionFactory = flowExecutor
163: .getExecutionFactory();
164: } else {
165: defaultExecutionFactory = new FlowExecutionImplFactory();
166: }
167: }
168: return defaultExecutionFactory;
169: }
170: }
171:
172: /**
173: * Returns the flow executor providing access to services used by the Spring
174: * Web Flow JSF integration. Searches for a bean in the root web application
175: * context named {@link #FLOW_EXECUTOR_BEAN_NAME}. If no such bean exists
176: * returns null.
177: * @param context the faces context
178: * @return the flow executor, or null if no such bean exists
179: */
180: private synchronized static FlowExecutorImpl getFlowExecutor(
181: FacesContext context) {
182: ApplicationContext ac = FacesContextUtils
183: .getRequiredWebApplicationContext(context);
184: if (ac.containsBean(FLOW_EXECUTOR_BEAN_NAME)) {
185: return (FlowExecutorImpl) ac.getBean(
186: FLOW_EXECUTOR_BEAN_NAME, FlowExecutorImpl.class);
187: } else {
188: return null;
189: }
190: }
191: }
|