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.xml;
017:
018: import java.util.Stack;
019:
020: import org.springframework.beans.BeansException;
021: import org.springframework.beans.factory.BeanFactory;
022: import org.springframework.binding.convert.ConversionService;
023: import org.springframework.binding.expression.ExpressionParser;
024: import org.springframework.core.io.ResourceLoader;
025: import org.springframework.webflow.action.BeanInvokingActionFactory;
026: import org.springframework.webflow.engine.Flow;
027: import org.springframework.webflow.engine.FlowAttributeMapper;
028: import org.springframework.webflow.engine.FlowExecutionExceptionHandler;
029: import org.springframework.webflow.engine.TargetStateResolver;
030: import org.springframework.webflow.engine.TransitionCriteria;
031: import org.springframework.webflow.engine.ViewSelector;
032: import org.springframework.webflow.engine.builder.FlowArtifactFactory;
033: import org.springframework.webflow.engine.builder.FlowArtifactLookupException;
034: import org.springframework.webflow.engine.builder.FlowServiceLocator;
035: import org.springframework.webflow.execution.Action;
036:
037: /**
038: * Flow service locator that searches flow-local registries first before querying the global, externally
039: * managed flow service locator.
040: * <p>
041: * Internal helper class of the {@link org.springframework.webflow.engine.builder.xml.XmlFlowBuilder}.
042: * Package private to highlight it's non-public nature.
043: *
044: * @see org.springframework.webflow.engine.builder.xml.XmlFlowBuilder
045: *
046: * @author Keith Donald
047: */
048: class LocalFlowServiceLocator implements FlowServiceLocator {
049:
050: /**
051: * The stack of registries.
052: */
053: private Stack localRegistries = new Stack();
054:
055: /**
056: * The parent service locator.
057: */
058: private FlowServiceLocator parent;
059:
060: /**
061: * Creates a new local service locator.
062: * @param parent the parent service locator
063: */
064: public LocalFlowServiceLocator(FlowServiceLocator parent) {
065: this .parent = parent;
066: }
067:
068: /**
069: * Push a new registry onto the stack.
070: * @param registry the local registry
071: */
072: public void push(LocalFlowServiceRegistry registry) {
073: localRegistries.push(registry);
074: }
075:
076: /**
077: * Pops all registries off the stack until the stack is empty.
078: */
079: public void diposeOfAnyRegistries() {
080: while (!localRegistries.isEmpty()) {
081: pop();
082: }
083: }
084:
085: /**
086: * Pop a registry off the stack.
087: */
088: public LocalFlowServiceRegistry pop() {
089: return (LocalFlowServiceRegistry) localRegistries.pop();
090: }
091:
092: /**
093: * Returns the top registry on the stack.
094: */
095: public LocalFlowServiceRegistry top() {
096: return (LocalFlowServiceRegistry) localRegistries.peek();
097: }
098:
099: /**
100: * Returns true if this locator has no local registries.
101: */
102: public boolean isEmpty() {
103: return localRegistries.isEmpty();
104: }
105:
106: // implementing FlowServiceLocator
107:
108: public Flow getSubflow(String id)
109: throws FlowArtifactLookupException {
110: Flow currentFlow = getCurrentFlow();
111: // quick check for recursive subflow
112: if (currentFlow.getId().equals(id)) {
113: return currentFlow;
114: }
115: // check local inline flows
116: if (currentFlow.containsInlineFlow(id)) {
117: return currentFlow.getInlineFlow(id);
118: }
119: // check externally managed top-level flows
120: return parent.getSubflow(id);
121: }
122:
123: public Action getAction(String id)
124: throws FlowArtifactLookupException {
125: if (containsBean(id)) {
126: return (Action) getBean(id, Action.class);
127: } else {
128: return parent.getAction(id);
129: }
130: }
131:
132: public FlowAttributeMapper getAttributeMapper(String id)
133: throws FlowArtifactLookupException {
134: if (containsBean(id)) {
135: return (FlowAttributeMapper) getBean(id,
136: FlowAttributeMapper.class);
137: } else {
138: return parent.getAttributeMapper(id);
139: }
140: }
141:
142: public TransitionCriteria getTransitionCriteria(String id)
143: throws FlowArtifactLookupException {
144: if (containsBean(id)) {
145: return (TransitionCriteria) getBean(id,
146: TransitionCriteria.class);
147: } else {
148: return parent.getTransitionCriteria(id);
149: }
150: }
151:
152: public TargetStateResolver getTargetStateResolver(String id)
153: throws FlowArtifactLookupException {
154: if (containsBean(id)) {
155: return (TargetStateResolver) getBean(id,
156: TargetStateResolver.class);
157: } else {
158: return parent.getTargetStateResolver(id);
159: }
160: }
161:
162: public ViewSelector getViewSelector(String id)
163: throws FlowArtifactLookupException {
164: if (containsBean(id)) {
165: return (ViewSelector) getBean(id, ViewSelector.class);
166: } else {
167: return parent.getViewSelector(id);
168: }
169: }
170:
171: public FlowExecutionExceptionHandler getExceptionHandler(String id)
172: throws FlowArtifactLookupException {
173: if (containsBean(id)) {
174: return (FlowExecutionExceptionHandler) getBean(id,
175: FlowExecutionExceptionHandler.class);
176: } else {
177: return parent.getExceptionHandler(id);
178: }
179: }
180:
181: public FlowArtifactFactory getFlowArtifactFactory() {
182: return parent.getFlowArtifactFactory();
183: }
184:
185: public BeanInvokingActionFactory getBeanInvokingActionFactory() {
186: return parent.getBeanInvokingActionFactory();
187: }
188:
189: public BeanFactory getBeanFactory() {
190: return top().getBeanFactory();
191: }
192:
193: public ResourceLoader getResourceLoader() {
194: return parent.getResourceLoader();
195: }
196:
197: public ExpressionParser getExpressionParser() {
198: return parent.getExpressionParser();
199: }
200:
201: public ConversionService getConversionService() {
202: return parent.getConversionService();
203: }
204:
205: // internal helpers
206:
207: /**
208: * Returns the flow for the registry at the top of the stack.
209: */
210: protected Flow getCurrentFlow() {
211: return top().getFlow();
212: }
213:
214: /**
215: * Does this flow local service locator contain a bean defintion for the given id?
216: */
217: protected boolean containsBean(String id) {
218: if (localRegistries.isEmpty()) {
219: return false;
220: } else {
221: return getBeanFactory().containsBean(id);
222: }
223: }
224:
225: /**
226: * Get the identified bean and make sure it is of the required type.
227: */
228: protected Object getBean(String id, Class artifactType)
229: throws FlowArtifactLookupException {
230: try {
231: return getBeanFactory().getBean(id, artifactType);
232: } catch (BeansException e) {
233: throw new FlowArtifactLookupException(id, artifactType, e);
234: }
235: }
236: }
|