EMMA Coverage Report (generated Thu May 22 12:08:10 CDT 2014)
[all classes][org.springframework.batch.core.configuration.xml]

COVERAGE SUMMARY FOR SOURCE FILE [TaskletParser.java]

nameclass, %method, %block, %line, %
TaskletParser.java100% (1/1)100% (10/10)71%  (405/572)84%  (97/116)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TaskletParser100% (1/1)100% (10/10)71%  (405/572)84%  (97/116)
validateTaskletAttributesAndSubelements (Element, ParserContext, boolean, Str... 100% (1/1)21%  (40/188)36%  (10/28)
handleExceptionElement (Element, ParserContext, MutablePropertyValues, String... 100% (1/1)72%  (48/67)91%  (10/11)
<static initializer> 100% (1/1)100% (9/9)100% (2/2)
TaskletParser (): void 100% (1/1)100% (3/3)100% (1/1)
addExceptionClasses (String, Element, ManagedList, ParserContext): void 100% (1/1)100% (26/26)100% (5/5)
getTaskletAdapter (BeanMetadataElement, String): BeanMetadataElement 100% (1/1)100% (16/16)100% (4/4)
handleTaskletAttributes (Element, MutablePropertyValues): void 100% (1/1)100% (64/64)100% (17/17)
handleTaskletElement (Element, AbstractBeanDefinition, ParserContext): void 100% (1/1)100% (32/32)100% (8/8)
handleTransactionAttributesElement (Element, MutablePropertyValues): void 100% (1/1)100% (47/47)100% (13/13)
parseTasklet (Element, Element, AbstractBeanDefinition, ParserContext, boolea... 100% (1/1)100% (120/120)100% (27/27)

1/*
2 * Copyright 2006-2010 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.springframework.batch.core.configuration.xml;
17 
18import java.util.List;
19 
20import org.springframework.batch.core.step.tasklet.MethodInvokingTaskletAdapter;
21import org.springframework.beans.BeanMetadataElement;
22import org.springframework.beans.MutablePropertyValues;
23import org.springframework.beans.factory.config.BeanDefinition;
24import org.springframework.beans.factory.config.BeanDefinitionHolder;
25import org.springframework.beans.factory.config.RuntimeBeanReference;
26import org.springframework.beans.factory.config.TypedStringValue;
27import org.springframework.beans.factory.support.AbstractBeanDefinition;
28import org.springframework.beans.factory.support.BeanDefinitionBuilder;
29import org.springframework.beans.factory.support.ManagedList;
30import org.springframework.beans.factory.xml.ParserContext;
31import org.springframework.util.StringUtils;
32import org.springframework.util.xml.DomUtils;
33import org.w3c.dom.Element;
34 
35/**
36 * Parse a tasklet element for a step.
37 * 
38 * @author Dave Syer
39 * 
40 * @since 2.1
41 * 
42 */
43public class TaskletParser {
44 
45        /**
46         * 
47         */
48        private static final String TRANSACTION_MANAGER_ATTR = "transaction-manager";
49 
50        private static final String TASKLET_REF_ATTR = "ref";
51 
52        private static final String TASKLET_METHOD_ATTR = "method";
53 
54        private static final String BEAN_ELE = "bean";
55 
56        private static final String REF_ELE = "ref";
57 
58        private static final String TASK_EXECUTOR_ATTR = "task-executor";
59 
60        private static final String CHUNK_ELE = "chunk";
61 
62        private static final String TX_ATTRIBUTES_ELE = "transaction-attributes";
63 
64        private static final String MERGE_ATTR = "merge";
65 
66        private static final ChunkElementParser chunkElementParser = new ChunkElementParser();
67 
68        // TODO: BATCH-1689, make this StepListenerParser.taskletListenerMetaData()
69        private static final StepListenerParser stepListenerParser = new StepListenerParser();
70 
71        public void parseTasklet(Element stepElement, Element taskletElement, AbstractBeanDefinition bd,
72                        ParserContext parserContext, boolean stepUnderspecified) {
73 
74                bd.setBeanClass(StepParserStepFactoryBean.class);
75                bd.setAttribute("isNamespaceStep", true);
76 
77                String taskletRef = taskletElement.getAttribute(TASKLET_REF_ATTR);
78                String taskletMethod = taskletElement.getAttribute(TASKLET_METHOD_ATTR);
79                @SuppressWarnings("unchecked")
80                List<Element> chunkElements = DomUtils.getChildElementsByTagName(taskletElement, CHUNK_ELE);
81                @SuppressWarnings("unchecked")
82                List<Element> beanElements = DomUtils.getChildElementsByTagName(taskletElement, BEAN_ELE);
83                @SuppressWarnings("unchecked")
84                List<Element> refElements = DomUtils.getChildElementsByTagName(taskletElement, REF_ELE);
85 
86                validateTaskletAttributesAndSubelements(taskletElement, parserContext, stepUnderspecified, taskletRef,
87                                chunkElements, beanElements, refElements);
88 
89                if (!chunkElements.isEmpty()) {
90                        chunkElementParser.parse(chunkElements.get(0), bd, parserContext, stepUnderspecified);
91                }
92                else {
93                        BeanMetadataElement bme = null;
94                        if (StringUtils.hasText(taskletRef)) {
95                                bme = new RuntimeBeanReference(taskletRef);
96                        }
97                        else if (beanElements.size() == 1) {
98                                Element beanElement = beanElements.get(0);
99                                BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate().parseBeanDefinitionElement(
100                                                beanElement, bd);
101                                parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDefinitionHolder);
102                                bme = beanDefinitionHolder;
103                        }
104                        else if (refElements.size() == 1) {
105                                bme = (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElements.get(0),
106                                                null);
107                        }
108 
109                        if (StringUtils.hasText(taskletMethod)) {
110                                bme = getTaskletAdapter(bme, taskletMethod);
111                        }
112 
113                        if (bme != null) {
114                                bd.getPropertyValues().addPropertyValue("tasklet", bme);
115                        }
116                }
117 
118                handleTaskletElement(taskletElement, bd, parserContext);
119        }
120 
121        /**
122         * Create a {@link MethodInvokingTaskletAdapter} for the POJO specified.
123         */
124        private BeanMetadataElement getTaskletAdapter(BeanMetadataElement bme, String taskletMethod) {
125                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingTaskletAdapter.class);
126                builder.addPropertyValue("targetMethod", taskletMethod);
127                builder.addPropertyValue("targetObject", bme);
128                return builder.getBeanDefinition();
129        }
130 
131        private void validateTaskletAttributesAndSubelements(Element taskletElement, ParserContext parserContext,
132                        boolean stepUnderspecified, String taskletRef, List<Element> chunkElements, List<Element> beanElements,
133                        List<Element> refElements) {
134                int total = (StringUtils.hasText(taskletRef) ? 1 : 0) + chunkElements.size() + beanElements.size()
135                                + refElements.size();
136 
137                StringBuilder found = new StringBuilder();
138                if (total > 1) {
139                        if (StringUtils.hasText(taskletRef)) {
140                                found.append("'" + TASKLET_REF_ATTR + "' attribute, ");
141                        }
142                        if (chunkElements.size() == 1) {
143                                found.append("<" + CHUNK_ELE + "/> element, ");
144                        }
145                        else if (chunkElements.size() > 1) {
146                                found.append(chunkElements.size() + " <" + CHUNK_ELE + "/> elements, ");
147                        }
148                        if (beanElements.size() == 1) {
149                                found.append("<" + BEAN_ELE + "/> element, ");
150                        }
151                        else if (beanElements.size() > 1) {
152                                found.append(beanElements.size() + " <" + BEAN_ELE + "/> elements, ");
153                        }
154                        if (refElements.size() == 1) {
155                                found.append("<" + REF_ELE + "/> element, ");
156                        }
157                        else if (refElements.size() > 1) {
158                                found.append(refElements.size() + " <" + REF_ELE + "/> elements, ");
159                        }
160                        found.delete(found.length() - 2, found.length());
161                }
162                else {
163                        found.append("None");
164                }
165 
166                String error = null;
167                if (stepUnderspecified) {
168                        if (total > 1) {
169                                error = "may not have more than";
170                        }
171                }
172                else if (total != 1) {
173                        error = "must have exactly";
174                }
175 
176                if (error != null) {
177                        parserContext.getReaderContext().error(
178                                        "The <" + taskletElement.getTagName() + "/> element " + error + " one of: '" + TASKLET_REF_ATTR
179                                                        + "' attribute, <" + CHUNK_ELE + "/> element, <" + BEAN_ELE + "/> attribute, or <"
180                                                        + REF_ELE + "/> element.  Found: " + found + ".", taskletElement);
181                }
182        }
183 
184        private void handleTaskletElement(Element taskletElement, AbstractBeanDefinition bd, ParserContext parserContext) {
185                MutablePropertyValues propertyValues = bd.getPropertyValues();
186                handleTaskletAttributes(taskletElement, propertyValues);
187                handleTransactionAttributesElement(taskletElement, propertyValues);
188                stepListenerParser.handleListenersElement(taskletElement, bd, parserContext);
189                handleExceptionElement(taskletElement, parserContext, propertyValues, "no-rollback-exception-classes",
190                                "noRollbackExceptionClasses");
191                bd.setRole(BeanDefinition.ROLE_SUPPORT);
192                bd.setSource(parserContext.extractSource(taskletElement));
193        }
194 
195        private void handleTransactionAttributesElement(Element stepElement, MutablePropertyValues propertyValues) {
196                @SuppressWarnings("unchecked")
197                List<Element> txAttrElements = DomUtils.getChildElementsByTagName(stepElement, TX_ATTRIBUTES_ELE);
198                if (txAttrElements.size() == 1) {
199                        Element txAttrElement = txAttrElements.get(0);
200                        String propagation = txAttrElement.getAttribute("propagation");
201                        if (StringUtils.hasText(propagation)) {
202                                propertyValues.addPropertyValue("propagation", propagation);
203                        }
204                        String isolation = txAttrElement.getAttribute("isolation");
205                        if (StringUtils.hasText(isolation)) {
206                                propertyValues.addPropertyValue("isolation", isolation);
207                        }
208                        String timeout = txAttrElement.getAttribute("timeout");
209                        if (StringUtils.hasText(timeout)) {
210                                propertyValues.addPropertyValue("transactionTimeout", timeout);
211                        }
212                }
213        }
214 
215        @SuppressWarnings("unchecked")
216        private void handleExceptionElement(Element element, ParserContext parserContext,
217                        MutablePropertyValues propertyValues, String exceptionListName, String propertyName) {
218                List<Element> children = DomUtils.getChildElementsByTagName(element, exceptionListName);
219                if (children.size() == 1) {
220                        Element exceptionClassesElement = children.get(0);
221                        ManagedList list = new ManagedList();
222                        list.setMergeEnabled(exceptionClassesElement.hasAttribute(MERGE_ATTR)
223                                        && Boolean.valueOf(exceptionClassesElement.getAttribute(MERGE_ATTR)));
224                        addExceptionClasses("include", exceptionClassesElement, list, parserContext);
225                        propertyValues.addPropertyValue(propertyName, list);
226                }
227                else if (children.size() > 1) {
228                        parserContext.getReaderContext().error(
229                                        "The <" + exceptionListName + "/> element may not appear more than once in a single <"
230                                                        + element.getNodeName() + "/>.", element);
231                }
232        }
233 
234        @SuppressWarnings("unchecked")
235        private void addExceptionClasses(String elementName, Element exceptionClassesElement, ManagedList list,
236                        ParserContext parserContext) {
237                for (Element child : (List<Element>) DomUtils.getChildElementsByTagName(exceptionClassesElement, elementName)) {
238                        String className = child.getAttribute("class");
239                        list.add(new TypedStringValue(className, Class.class));
240                }
241        }
242 
243        private void handleTaskletAttributes(Element taskletElement, MutablePropertyValues propertyValues) {
244                String transactionManagerRef = taskletElement.getAttribute(TRANSACTION_MANAGER_ATTR);
245                if (StringUtils.hasText(transactionManagerRef)) {
246                        propertyValues.addPropertyValue("transactionManager", new RuntimeBeanReference(transactionManagerRef));
247                }
248                String startLimit = taskletElement.getAttribute("start-limit");
249                if (StringUtils.hasText(startLimit)) {
250                        propertyValues.addPropertyValue("startLimit", startLimit);
251                }
252                String allowStartIfComplete = taskletElement.getAttribute("allow-start-if-complete");
253                if (StringUtils.hasText(allowStartIfComplete)) {
254                        propertyValues.addPropertyValue("allowStartIfComplete", allowStartIfComplete);
255                }
256                String taskExecutorBeanId = taskletElement.getAttribute(TASK_EXECUTOR_ATTR);
257                if (StringUtils.hasText(taskExecutorBeanId)) {
258                        RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId);
259                        propertyValues.addPropertyValue("taskExecutor", taskExecutorRef);
260                }
261                String throttleLimit = taskletElement.getAttribute("throttle-limit");
262                if (StringUtils.hasText(throttleLimit)) {
263                        propertyValues.addPropertyValue("throttleLimit", throttleLimit);
264                }
265        }
266 
267}

[all classes][org.springframework.batch.core.configuration.xml]
EMMA 2.0.5312 (C) Vladimir Roubtsov