EMMA Coverage Report (generated Fri Aug 21 15:59:46 BST 2009)
[all classes][org.springframework.batch.core.configuration.xml]

COVERAGE SUMMARY FOR SOURCE FILE [AbstractStepParser.java]

nameclass, %method, %block, %line, %
AbstractStepParser.java100% (1/1)100% (10/10)85%  (400/473)88%  (99/113)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AbstractStepParser100% (1/1)100% (10/10)85%  (400/473)88%  (99/113)
parseTasklet (Element, Element, AbstractBeanDefinition, ParserContext, boolea... 100% (1/1)55%  (50/91)60%  (12/20)
handleExceptionElement (Element, ParserContext, MutablePropertyValues, String... 100% (1/1)75%  (55/73)80%  (12/15)
parseStep (Element, ParserContext, String): AbstractBeanDefinition 100% (1/1)81%  (61/75)83%  (15/18)
<static initializer> 100% (1/1)100% (9/9)100% (3/3)
AbstractStepParser (): void 100% (1/1)100% (3/3)100% (1/1)
checkStepAttributes (Element, MutablePropertyValues): void 100% (1/1)100% (23/23)100% (7/7)
handleListenersElement (Element, MutablePropertyValues, ParserContext): void 100% (1/1)100% (75/75)100% (16/16)
handleTransactionAttributesElement (Element, MutablePropertyValues, ParserCon... 100% (1/1)100% (47/47)100% (13/13)
parseTaskletRef (String, MutablePropertyValues): void 100% (1/1)100% (13/13)100% (4/4)
setUpBeanDefinitionForTaskletStep (Element, AbstractBeanDefinition, ParserCon... 100% (1/1)100% (64/64)100% (17/17)

1/*
2 * Copyright 2006-2009 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.Arrays;
19import java.util.List;
20 
21import org.springframework.beans.MutablePropertyValues;
22import org.springframework.beans.factory.config.BeanDefinition;
23import org.springframework.beans.factory.config.RuntimeBeanReference;
24import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
25import org.springframework.beans.factory.support.AbstractBeanDefinition;
26import org.springframework.beans.factory.support.GenericBeanDefinition;
27import org.springframework.beans.factory.support.ManagedList;
28import org.springframework.beans.factory.xml.ParserContext;
29import org.springframework.util.StringUtils;
30import org.springframework.util.xml.DomUtils;
31import org.w3c.dom.Element;
32 
33/**
34 * Internal parser for the &lt;step/&gt; elements inside a job. A step element
35 * references a bean definition for a
36 * {@link org.springframework.batch.core.Step} and goes on to (optionally) list
37 * a set of transitions from that step to others with &lt;next on="pattern"
38 * to="stepName"/&gt;. Used by the {@link JobParser}.
39 * 
40 * @see JobParser
41 * 
42 * @author Dave Syer
43 * @author Thomas Risberg
44 * @since 2.0
45 */
46public abstract class AbstractStepParser {
47 
48        protected static final String ID_ATTR = "id";
49 
50        private static final String PARENT_ATTR = "parent";
51 
52        private static final String TASKLET_REF_ATTR = "ref";
53 
54        private static final String TASKLET_ELE = "tasklet";
55 
56        private static final String CHUNK_ELE = "chunk";
57 
58        private static final String LISTENERS_ELE = "listeners";
59 
60        private static final String MERGE_ATTR = "merge";
61 
62        private static final String TX_ATTRIBUTES_ELE = "transaction-attributes";
63 
64        private static final String JOB_REPO_ATTR = "job-repository";
65 
66        private static final ChunkElementParser chunkElementParser = new ChunkElementParser();
67 
68        private static final StepListenerParser stepListenerParser = new StepListenerParser();
69 
70        /**
71         * @param stepElement The &lt;step/&gt; element
72         * @param parserContext
73         * @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
74         * from the enclosing tag. Use 'null' if unknown.
75         */
76        protected AbstractBeanDefinition parseStep(Element stepElement, ParserContext parserContext, String jobFactoryRef) {
77 
78                AbstractBeanDefinition bd = new GenericBeanDefinition();
79 
80                @SuppressWarnings("unchecked")
81                List<Element> taskletElements = (List<Element>) DomUtils.getChildElementsByTagName(stepElement, TASKLET_ELE);
82                if (taskletElements.size() == 1) {
83                        boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
84                        parseTasklet(stepElement, taskletElements.get(0), bd, parserContext, stepUnderspecified);
85                }
86                else if (taskletElements.size() > 1) {
87                        parserContext.getReaderContext().error(
88                                        "The '<" + TASKLET_ELE + "/>' element may not appear more than once in a single <"
89                                                        + stepElement.getNodeName() + "/>.", stepElement);
90                }
91 
92                String parentRef = stepElement.getAttribute(PARENT_ATTR);
93                if (StringUtils.hasText(parentRef)) {
94                        bd.setParentName(parentRef);
95                }
96 
97                String isAbstract = stepElement.getAttribute("abstract");
98                if (StringUtils.hasText(isAbstract)) {
99                        bd.setAbstract(Boolean.valueOf(isAbstract));
100                }
101 
102                if (StringUtils.hasText(jobFactoryRef)) {
103                        bd.setAttribute("jobParserJobFactoryBeanRef", jobFactoryRef);
104                }
105 
106                return bd;
107 
108        }
109 
110        private void parseTasklet(Element stepElement, Element taskletElement, AbstractBeanDefinition bd,
111                        ParserContext parserContext, boolean stepUnderspecified) {
112 
113                bd.setBeanClass(StepParserStepFactoryBean.class);
114                bd.setAttribute("isNamespaceStep", true);
115 
116                String taskletRef = taskletElement.getAttribute(TASKLET_REF_ATTR);
117                @SuppressWarnings("unchecked")
118                List<Element> chunkElements = (List<Element>) DomUtils.getChildElementsByTagName(taskletElement, CHUNK_ELE);
119                if (StringUtils.hasText(taskletRef)) {
120                        if (chunkElements.size() > 0) {
121                                parserContext.getReaderContext().error(
122                                                "The <" + CHUNK_ELE + "/> element can't be combined with the '" + TASKLET_REF_ATTR + "=\""
123                                                                + taskletRef + "\"' attribute specification for <" + taskletElement.getNodeName()
124                                                                + "/>", taskletElement);
125                        }
126                        parseTaskletRef(taskletRef, bd.getPropertyValues());
127                }
128                else if (chunkElements.size() == 1) {
129                        chunkElementParser.parse(chunkElements.get(0), bd, parserContext, stepUnderspecified);
130                }
131                else if (!stepUnderspecified) {
132                        parserContext.getReaderContext().error(
133                                        "Step [" + stepElement.getAttribute(ID_ATTR) + "] has neither a <" + CHUNK_ELE
134                                                        + "/> element nor a '" + TASKLET_REF_ATTR + "' attribute referencing a Tasklet.",
135                                        taskletElement);
136                }
137 
138                setUpBeanDefinitionForTaskletStep(taskletElement, bd, parserContext);
139        }
140 
141        private void parseTaskletRef(String taskletRef, MutablePropertyValues propertyValues) {
142                if (StringUtils.hasText(taskletRef)) {
143                        RuntimeBeanReference taskletBeanRef = new RuntimeBeanReference(taskletRef);
144                        propertyValues.addPropertyValue("tasklet", taskletBeanRef);
145                }
146        }
147 
148        private void setUpBeanDefinitionForTaskletStep(Element taskletElement, AbstractBeanDefinition bd,
149                        ParserContext parserContext) {
150 
151                MutablePropertyValues propertyValues = bd.getPropertyValues();
152 
153                checkStepAttributes(taskletElement, propertyValues);
154 
155                String jobRepositoryRef = taskletElement.getAttribute(JOB_REPO_ATTR);
156                if (StringUtils.hasText(jobRepositoryRef)) {
157                        RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(jobRepositoryRef);
158                        propertyValues.addPropertyValue("jobRepository", jobRepositoryBeanRef);
159                }
160 
161                String transactionManagerRef = taskletElement.getAttribute("transaction-manager");
162                if (StringUtils.hasText(transactionManagerRef)) {
163                        RuntimeBeanReference transactionManagerBeanRef = new RuntimeBeanReference(transactionManagerRef);
164                        propertyValues.addPropertyValue("transactionManager", transactionManagerBeanRef);
165                }
166 
167                handleTransactionAttributesElement(taskletElement, propertyValues, parserContext);
168 
169                handleListenersElement(taskletElement, propertyValues, parserContext);
170 
171                handleExceptionElement(taskletElement, parserContext, propertyValues, "no-rollback-exception-classes",
172                                "noRollbackExceptionClasses");
173 
174                bd.setRole(BeanDefinition.ROLE_SUPPORT);
175 
176                bd.setSource(parserContext.extractSource(taskletElement));
177 
178        }
179 
180        private void handleTransactionAttributesElement(Element stepElement, MutablePropertyValues propertyValues,
181                        ParserContext parserContext) {
182                @SuppressWarnings("unchecked")
183                List<Element> txAttrElements = DomUtils.getChildElementsByTagName(stepElement, TX_ATTRIBUTES_ELE);
184                if (txAttrElements.size() == 1) {
185                        Element txAttrElement = txAttrElements.get(0);
186                        String propagation = txAttrElement.getAttribute("propagation");
187                        if (StringUtils.hasText(propagation)) {
188                                propertyValues.addPropertyValue("propagation", propagation);
189                        }
190                        String isolation = txAttrElement.getAttribute("isolation");
191                        if (StringUtils.hasText(isolation)) {
192                                propertyValues.addPropertyValue("isolation", isolation);
193                        }
194                        String timeout = txAttrElement.getAttribute("timeout");
195                        if (StringUtils.hasText(timeout)) {
196                                propertyValues.addPropertyValue("transactionTimeout", timeout);
197                        }
198                }
199        }
200 
201        @SuppressWarnings("unchecked")
202        public static void handleExceptionElement(Element element, ParserContext parserContext,
203                        MutablePropertyValues propertyValues, String subElementName, String propertyName) {
204                List<Element> children = DomUtils.getChildElementsByTagName(element, subElementName);
205                if (children.size() == 1) {
206                        Element child = children.get(0);
207                        String exceptions = DomUtils.getTextValue(child);
208                        String[] exceptionArray = StringUtils.tokenizeToStringArray(exceptions, ",\n");
209                        ManagedList managedList = new ManagedList();
210                        managedList.setMergeEnabled(child.hasAttribute(MERGE_ATTR)
211                                        && Boolean.valueOf(child.getAttribute(MERGE_ATTR)));
212                        managedList.addAll(Arrays.asList(exceptionArray));
213                        propertyValues.addPropertyValue(propertyName, managedList);
214                }
215                else if (children.size() > 1) {
216                        parserContext.getReaderContext().error(
217                                        "The <" + subElementName + "/> element may not appear more than once in a single <"
218                                                        + element.getNodeName() + "/>.", element);
219                }
220 
221        }
222 
223        private void checkStepAttributes(Element stepElement, MutablePropertyValues propertyValues) {
224                String startLimit = stepElement.getAttribute("start-limit");
225                if (StringUtils.hasText(startLimit)) {
226                        propertyValues.addPropertyValue("startLimit", startLimit);
227                }
228                String allowStartIfComplete = stepElement.getAttribute("allow-start-if-complete");
229                if (StringUtils.hasText(allowStartIfComplete)) {
230                        propertyValues.addPropertyValue("allowStartIfComplete", allowStartIfComplete);
231                }
232        }
233 
234        @SuppressWarnings("unchecked")
235        private void handleListenersElement(Element stepElement, MutablePropertyValues propertyValues,
236                        ParserContext parserContext) {
237                List<Element> listenersElements = DomUtils.getChildElementsByTagName(stepElement, LISTENERS_ELE);
238                if (listenersElements.size() == 1) {
239                        Element listenersElement = listenersElements.get(0);
240                        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(listenersElement.getTagName(),
241                                        parserContext.extractSource(stepElement));
242                        parserContext.pushContainingComponent(compositeDef);
243                        ManagedList listenerBeans = new ManagedList();
244                        listenerBeans.setMergeEnabled(listenersElement.hasAttribute(MERGE_ATTR)
245                                        && Boolean.valueOf(listenersElement.getAttribute(MERGE_ATTR)));
246                        List<Element> listenerElements = DomUtils.getChildElementsByTagName(listenersElement, "listener");
247                        if (listenerElements != null) {
248                                for (Element listenerElement : listenerElements) {
249                                        listenerBeans.add(stepListenerParser.parse(listenerElement, parserContext));
250                                }
251                        }
252                        propertyValues.addPropertyValue("listeners", listenerBeans);
253                        parserContext.popAndRegisterContainingComponent();
254                }
255        }
256 
257}

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