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.config;
017:
018: import org.springframework.beans.factory.support.AbstractBeanDefinition;
019: import org.springframework.beans.factory.support.BeanDefinitionBuilder;
020: import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
021: import org.springframework.beans.factory.xml.BeanDefinitionParser;
022: import org.springframework.beans.factory.xml.ParserContext;
023: import org.springframework.util.StringUtils;
024: import org.springframework.util.xml.DomUtils;
025: import org.w3c.dom.Element;
026:
027: /**
028: * {@link BeanDefinitionParser} for the <code><executor></code> tag.
029: *
030: * @author Ben Hale
031: * @author Christian Dupuis
032: */
033: class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
034:
035: // elements and attributes
036:
037: private static final String CONVERSATION_MANAGER_REF_ATTRIBUTE = "conversation-manager-ref";
038:
039: private static final String EXECUTION_ATTRIBUTES_ELEMENT = "execution-attributes";
040:
041: private static final String EXECUTION_LISTENERS_ELEMENT = "execution-listeners";
042:
043: private static final String MAX_CONTINUATIONS_ATTRIBUTE = "max-continuations";
044:
045: private static final String MAX_CONVERSATIONS_ATTRIBUTE = "max-conversations";
046:
047: private static final String REGISTRY_REF_ATTRIBUTE = "registry-ref";
048:
049: private static final String REPOSITORY_ELEMENT = "repository";
050:
051: private static final String REPOSITORY_TYPE_ATTRIBUTE = "repository-type";
052:
053: private static final String TYPE_ATTRIBUTE = "type";
054:
055: // properties
056:
057: private static final String CONVERSATION_MANAGER_PROPERTY = "conversationManager";
058:
059: private static final String DEFINITION_LOCATOR_PROPERTY = "definitionLocator";
060:
061: private static final String EXECUTION_ATTRIBUTES_PROPERTY = "executionAttributes";
062:
063: private static final String EXECUTION_LISTENER_LOADER_PROPERTY = "executionListenerLoader";
064:
065: private static final String MAX_CONTINUATIONS_PROPERTY = "maxContinuations";
066:
067: private static final String MAX_CONVERSATIONS_PROPERTY = "maxConversations";
068:
069: private static final String REPOSITORY_TYPE_PROPERTY = "repositoryType";
070:
071: protected AbstractBeanDefinition parseInternal(Element element,
072: ParserContext parserContext) {
073: BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
074: .rootBeanDefinition(FlowExecutorFactoryBean.class);
075: definitionBuilder.setSource(parserContext
076: .extractSource(element));
077: definitionBuilder.addPropertyReference(
078: DEFINITION_LOCATOR_PROPERTY, getRegistryRef(element,
079: parserContext));
080: addExecutionAttributes(element, parserContext,
081: definitionBuilder);
082: addExecutionListenerLoader(element, parserContext,
083: definitionBuilder);
084: configureRepository(element, definitionBuilder, parserContext);
085: return definitionBuilder.getBeanDefinition();
086: }
087:
088: /**
089: * Configures a repository based on the <code>repository-type</code> attribute
090: * or a <code>repository</code> tag.
091: * @param element the root element to extract repository configuration from
092: * @param definitionBuilder the builder
093: * @param parserContext the parserContext
094: */
095: private void configureRepository(Element element,
096: BeanDefinitionBuilder definitionBuilder,
097: ParserContext parserContext) {
098: Element repositoryElement = DomUtils.getChildElementByTagName(
099: element, REPOSITORY_ELEMENT);
100: String repositoryTypeAttribute = getRepositoryType(element);
101: if (repositoryElement != null) {
102: if (StringUtils.hasText(repositoryTypeAttribute)) {
103: parserContext
104: .getReaderContext()
105: .error(
106: "The 'repositoryType' attribute of the 'executor' element must "
107: + "not have a value if there is a 'repository' element",
108: element);
109: }
110: definitionBuilder.addPropertyValue(
111: REPOSITORY_TYPE_PROPERTY,
112: getType(repositoryElement));
113: configureContinuations(repositoryElement,
114: definitionBuilder, parserContext);
115: configureConversationManager(repositoryElement,
116: definitionBuilder, parserContext);
117: } else if (StringUtils.hasText(repositoryTypeAttribute)) {
118: definitionBuilder.addPropertyValue(
119: REPOSITORY_TYPE_PROPERTY, repositoryTypeAttribute);
120: }
121: }
122:
123: /**
124: * Configure the max continuations setting.
125: * @param repositoryElement the repository element
126: * @param definitionBuilder the builder
127: * @param parserContext the parserContext
128: */
129: private void configureContinuations(Element repositoryElement,
130: BeanDefinitionBuilder definitionBuilder,
131: ParserContext parserContext) {
132: String maxContinuations = getMaxContinuations(repositoryElement);
133: if (StringUtils.hasText(maxContinuations)) {
134: if (!getType(repositoryElement).equals("CONTINUATION")) {
135: parserContext
136: .getReaderContext()
137: .error(
138: "The 'max-continuations' attribute of the 'repository' element must not "
139: + "have a value if the 'type' attribute is not 'continuation'",
140: repositoryElement);
141: }
142: definitionBuilder.addPropertyValue(
143: MAX_CONTINUATIONS_PROPERTY, maxContinuations);
144: }
145: }
146:
147: /**
148: * Configure the conversation manager
149: * @param repositoryElement the repository element
150: * @param definitionBuilder the builder
151: * @param parserContext the parserContext
152: */
153: private void configureConversationManager(
154: Element repositoryElement,
155: BeanDefinitionBuilder definitionBuilder,
156: ParserContext parserContext) {
157: String conversationManagerRef = getConversationManagerRef(repositoryElement);
158: String maxConversations = getMaxConversations(repositoryElement);
159: if (StringUtils.hasText(conversationManagerRef)) {
160: if (StringUtils.hasText(maxConversations)) {
161: parserContext
162: .getReaderContext()
163: .error(
164: "The 'max-conversations' attribute of the 'repository' element must not "
165: + "have a value if there is a value for the 'conversation-manager-ref' attribute",
166: repositoryElement);
167: }
168: definitionBuilder.addPropertyReference(
169: CONVERSATION_MANAGER_PROPERTY,
170: conversationManagerRef);
171: } else if (StringUtils.hasText(maxConversations)) {
172: definitionBuilder.addPropertyValue(
173: MAX_CONVERSATIONS_PROPERTY, maxConversations);
174: }
175: }
176:
177: /**
178: * Returns the name of the registry detailed in the bean definition.
179: * @param element the element to extract the registry name from
180: * @return the name of the registry
181: * @param parserContext the parserContext
182: */
183: private String getRegistryRef(Element element,
184: ParserContext parserContext) {
185: String registryRef = element
186: .getAttribute(REGISTRY_REF_ATTRIBUTE);
187: if (!StringUtils.hasText(registryRef)) {
188: parserContext
189: .getReaderContext()
190: .error(
191: "The 'registry-ref' attribute of the 'executor' element must have a value",
192: element);
193: }
194: return registryRef;
195: }
196:
197: /**
198: * Returns the name of the repository type enum field detailed in the bean
199: * definition.
200: * @param element the element to extract the repository type from
201: * @return the type of the repository
202: */
203: private String getRepositoryType(Element element) {
204: return element.getAttribute(REPOSITORY_TYPE_ATTRIBUTE)
205: .toUpperCase();
206: }
207:
208: /**
209: * Returns the name of the repository type enum field detailed in the bean
210: * definition.
211: * @param element the element to extract the repository type from
212: * @return the type of the repository
213: */
214: private String getType(Element element) {
215: return element.getAttribute(TYPE_ATTRIBUTE).toUpperCase();
216: }
217:
218: /**
219: * Returns the maximum number of continuations detailed in the bean definition.
220: * @param element the element to extract the max continuations from
221: * @return the max continuations
222: */
223: private String getMaxContinuations(Element element) {
224: return element.getAttribute(MAX_CONTINUATIONS_ATTRIBUTE);
225: }
226:
227: /**
228: * Returns the maximum number of conversations detailed in the bean definition.
229: * @param element the element to extract the max conversations from
230: * @return the max conversations
231: */
232: private String getMaxConversations(Element element) {
233: return element.getAttribute(MAX_CONVERSATIONS_ATTRIBUTE);
234: }
235:
236: /**
237: * Returns the name of the conversation manager detailed in the bean definition.
238: * @param element the element to extract the conversation manager name from
239: * @return the name of the conversation manager
240: */
241: private String getConversationManagerRef(Element element) {
242: return element.getAttribute(CONVERSATION_MANAGER_REF_ATTRIBUTE);
243: }
244:
245: /**
246: * Parse execution attribute definitions contained in given element.
247: */
248: private void addExecutionAttributes(Element element,
249: ParserContext parserContext,
250: BeanDefinitionBuilder definitionBuilder) {
251: Element attributesElement = DomUtils.getChildElementByTagName(
252: element, EXECUTION_ATTRIBUTES_ELEMENT);
253: if (attributesElement != null) {
254: definitionBuilder.addPropertyValue(
255: EXECUTION_ATTRIBUTES_PROPERTY, parserContext
256: .getDelegate().parseCustomElement(
257: attributesElement,
258: definitionBuilder
259: .getBeanDefinition()));
260: }
261: }
262:
263: /**
264: * Parse execution listener definitions contained in given element.
265: */
266: private void addExecutionListenerLoader(Element element,
267: ParserContext parserContext,
268: BeanDefinitionBuilder definitionBuilder) {
269: Element listenersElement = DomUtils.getChildElementByTagName(
270: element, EXECUTION_LISTENERS_ELEMENT);
271: if (listenersElement != null) {
272: definitionBuilder.addPropertyValue(
273: EXECUTION_LISTENER_LOADER_PROPERTY, parserContext
274: .getDelegate().parseCustomElement(
275: listenersElement,
276: definitionBuilder
277: .getBeanDefinition()));
278: }
279: }
280: }
|