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

COVERAGE SUMMARY FOR SOURCE FILE [FlowJob.java]

nameclass, %method, %block, %line, %
FlowJob.java100% (2/2)100% (19/19)95%  (233/244)96%  (52.8/55)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class FlowJob100% (1/1)100% (8/8)93%  (86/92)96%  (22/23)
doExecute (JobExecution): void 100% (1/1)81%  (25/31)86%  (6/7)
FlowJob (): void 100% (1/1)100% (3/3)100% (2/2)
FlowJob (String): void 100% (1/1)100% (4/4)100% (2/2)
access$0 (FlowJob, Step, JobExecution): StepExecution 100% (1/1)100% (5/5)100% (1/1)
access$1 (FlowJob, StepExecution): void 100% (1/1)100% (4/4)100% (1/1)
getStep (String): Step 100% (1/1)100% (14/14)100% (4/4)
getStepNames (): Collection 100% (1/1)100% (27/27)100% (5/5)
setFlow (Flow): void 100% (1/1)100% (4/4)100% (2/2)
     
class FlowJob$JobFlowExecutor100% (1/1)100% (11/11)97%  (147/152)96%  (30.8/32)
executeStep (Step): String 100% (1/1)85%  (17/20)96%  (3.8/4)
findBatchStatus (FlowExecutionStatus): BatchStatus 100% (1/1)92%  (24/26)75%  (3/4)
FlowJob$JobFlowExecutor (FlowJob, JobExecution): void 100% (1/1)100% (21/21)100% (6/6)
FlowJob$JobFlowExecutor (FlowJob, JobExecution, FlowJob$JobFlowExecutor): void 100% (1/1)100% (5/5)100% (1/1)
abandonStepExecution (): void 100% (1/1)100% (20/20)100% (5/5)
addExitStatus (String): void 100% (1/1)100% (10/10)100% (2/2)
close (FlowExecution): void 100% (1/1)100% (5/5)100% (2/2)
getJobExecution (): JobExecution 100% (1/1)100% (3/3)100% (1/1)
getStepExecution (): StepExecution 100% (1/1)100% (5/5)100% (1/1)
isRestart (): boolean 100% (1/1)100% (15/15)100% (3/3)
updateJobExecutionStatus (FlowExecutionStatus): void 100% (1/1)100% (22/22)100% (4/4)

1/*
2 * Copyright 2006-2007 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.job.flow;
17 
18import java.util.Collection;
19import java.util.HashSet;
20 
21import org.springframework.batch.core.BatchStatus;
22import org.springframework.batch.core.ExitStatus;
23import org.springframework.batch.core.Job;
24import org.springframework.batch.core.JobExecution;
25import org.springframework.batch.core.JobExecutionException;
26import org.springframework.batch.core.JobInterruptedException;
27import org.springframework.batch.core.StartLimitExceededException;
28import org.springframework.batch.core.Step;
29import org.springframework.batch.core.StepExecution;
30import org.springframework.batch.core.job.AbstractJob;
31import org.springframework.batch.core.repository.JobRestartException;
32import org.springframework.batch.core.step.StepHolder;
33 
34/**
35 * Implementation of the {@link Job} interface that allows for complex flows of
36 * steps, rather than requiring sequential execution. In general, this job
37 * implementation was designed to be used behind a parser, allowing for a
38 * namespace to abstract away details.
39 * 
40 * @author Dave Syer
41 * @since 2.0
42 */
43public class FlowJob extends AbstractJob {
44 
45        private Flow flow;
46 
47        /**
48         * Create a {@link FlowJob} with null name and no flow (invalid state).
49         */
50        public FlowJob() {
51                super();
52        }
53 
54        /**
55         * Create a {@link FlowJob} with provided name and no flow (invalid state).
56         */
57        public FlowJob(String name) {
58                super(name);
59        }
60 
61        /**
62         * Public setter for the flow.
63         * 
64         * @param flow the flow to set
65         */
66        public void setFlow(Flow flow) {
67                this.flow = flow;
68        }
69 
70        /**
71         * {@inheritDoc}
72         */
73        @Override
74        public Step getStep(String stepName) {
75                State state = this.flow.getState(stepName);
76                if (state instanceof StepHolder) {
77                        return ((StepHolder) state).getStep();
78                }
79                return null;
80        }
81 
82        /**
83         * {@inheritDoc}
84         */
85        @Override
86        public Collection<String> getStepNames() {
87                Collection<String> steps = new HashSet<String>();
88                for (State state : flow.getStates()) {
89                        if (state instanceof StepHolder) {
90                                steps.add(state.getName());
91                        }
92                }
93                return steps;
94        }
95 
96        /**
97         * @see AbstractJob#doExecute(JobExecution)
98         */
99        @Override
100        protected void doExecute(final JobExecution execution) throws JobExecutionException {
101                try {
102                        JobFlowExecutor executor = new JobFlowExecutor(execution);
103                        executor.updateJobExecutionStatus(flow.start(executor).getStatus());
104                }
105                catch (FlowExecutionException e) {
106                        if (e.getCause() instanceof JobExecutionException) {
107                                throw (JobExecutionException) e.getCause();
108                        }
109                        throw new JobExecutionException("Flow execution ended unexpectedly", e);
110                }
111        }
112 
113        /**
114         * @author Dave Syer
115         * 
116         */
117        private class JobFlowExecutor implements FlowExecutor {
118 
119                private final ThreadLocal<StepExecution> stepExecutionHolder = new ThreadLocal<StepExecution>();
120 
121                private final JobExecution execution;
122 
123                private ExitStatus exitStatus = ExitStatus.EXECUTING;
124 
125                /**
126                 * @param execution
127                 */
128                private JobFlowExecutor(JobExecution execution) {
129                        this.execution = execution;
130                        stepExecutionHolder.set(null);
131                }
132 
133                public String executeStep(Step step) throws JobInterruptedException, JobRestartException,
134                                StartLimitExceededException {
135                        StepExecution stepExecution = handleStep(step, execution);
136                        stepExecutionHolder.set(stepExecution);
137                        return stepExecution == null ? ExitStatus.COMPLETED.getExitCode() : stepExecution.getExitStatus()
138                                        .getExitCode();
139                }
140 
141                public void abandonStepExecution() {
142                        StepExecution lastStepExecution = stepExecutionHolder.get();
143                        if (lastStepExecution != null && lastStepExecution.getStatus().isGreaterThan(BatchStatus.STOPPING)) {
144                                lastStepExecution.upgradeStatus(BatchStatus.ABANDONED);
145                                updateStepExecution(lastStepExecution);
146                        }
147                }
148 
149                public void updateJobExecutionStatus(FlowExecutionStatus status) {
150                        execution.setStatus(findBatchStatus(status));
151                        exitStatus = exitStatus.and(new ExitStatus(status.getName()));
152                        execution.setExitStatus(exitStatus);
153                }
154 
155                public JobExecution getJobExecution() {
156                        return execution;
157                }
158 
159                public StepExecution getStepExecution() {
160                        return stepExecutionHolder.get();
161                }
162 
163                public void close(FlowExecution result) {
164                        stepExecutionHolder.set(null);
165                }
166 
167                public boolean isRestart() {
168                        if (getStepExecution() != null && getStepExecution().getStatus() == BatchStatus.ABANDONED) {
169                                /*
170                                 * This is assumed to be the last step execution and it was
171                                 * marked abandoned, so we are in a restart of a stopped step.
172                                 * TODO: mark the step execution in some more definitive way?
173                                 */
174                                return true;
175                        }
176                        return execution.getStepExecutions().isEmpty();
177                }
178 
179                public void addExitStatus(String code) {
180                        exitStatus = exitStatus.and(new ExitStatus(code));
181                }
182 
183                /**
184                 * @param status
185                 * @return
186                 */
187                private BatchStatus findBatchStatus(FlowExecutionStatus status) {
188                        for (BatchStatus batchStatus : BatchStatus.values()) {
189                                if (status.getName().startsWith(batchStatus.toString())) {
190                                        return batchStatus;
191                                }
192                        }
193                        return BatchStatus.UNKNOWN;
194                }
195 
196        }
197 
198}

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