View Javadoc

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   */
16  package org.springframework.batch.core.job.flow;
17  
18  import java.util.Collection;
19  import java.util.Map;
20  import java.util.concurrent.ConcurrentHashMap;
21  
22  import org.springframework.batch.core.Job;
23  import org.springframework.batch.core.JobExecution;
24  import org.springframework.batch.core.JobExecutionException;
25  import org.springframework.batch.core.Step;
26  import org.springframework.batch.core.job.AbstractJob;
27  import org.springframework.batch.core.job.SimpleStepHandler;
28  import org.springframework.batch.core.step.StepHolder;
29  import org.springframework.batch.core.step.StepLocator;
30  
31  /**
32   * Implementation of the {@link Job} interface that allows for complex flows of
33   * steps, rather than requiring sequential execution. In general, this job
34   * implementation was designed to be used behind a parser, allowing for a
35   * namespace to abstract away details.
36   * 
37   * @author Dave Syer
38   * @since 2.0
39   */
40  public class FlowJob extends AbstractJob {
41  
42  	private Flow flow;
43  
44  	private Map<String, Step> stepMap = new ConcurrentHashMap<String, Step>();
45  
46  	private volatile boolean initialized = false;
47  
48  	/**
49  	 * Create a {@link FlowJob} with null name and no flow (invalid state).
50  	 */
51  	public FlowJob() {
52  		super();
53  	}
54  
55  	/**
56  	 * Create a {@link FlowJob} with provided name and no flow (invalid state).
57  	 */
58  	public FlowJob(String name) {
59  		super(name);
60  	}
61  
62  	/**
63  	 * Public setter for the flow.
64  	 * 
65  	 * @param flow the flow to set
66  	 */
67  	public void setFlow(Flow flow) {
68  		this.flow = flow;
69  	}
70  
71  	/**
72  	 * {@inheritDoc}
73  	 */
74  	@Override
75  	public Step getStep(String stepName) {
76  		if (!initialized) {
77  			init();
78  		}
79  		return stepMap.get(stepName);
80  	}
81  
82  	/**
83  	 * Initialize the step names
84  	 */
85  	private void init() {
86  		findSteps(flow, stepMap);
87  	}
88  
89  	/**
90  	 * @param flow
91  	 * @param map
92  	 */
93  	private void findSteps(Flow flow, Map<String, Step> map) {
94  
95  		for (State state : flow.getStates()) {
96  			if (state instanceof StepHolder) {
97  				Step step = ((StepHolder) state).getStep();
98  				String name = step.getName();
99  				stepMap.put(name, step);
100 			}
101 			else if (state instanceof FlowHolder) {
102 				for (Flow subflow : ((FlowHolder) state).getFlows()) {
103 					findSteps(subflow, map);
104 				}
105 			}
106 			else if (state instanceof StepLocator) {
107 				StepLocator locator = (StepLocator) state;
108 				for (String name : locator.getStepNames()) {
109 					map.put(name, locator.getStep(name));
110 				}
111 			}
112 		}
113 
114 	}
115 
116 	/**
117 	 * {@inheritDoc}
118 	 */
119 	@Override
120 	public Collection<String> getStepNames() {
121 		if (!initialized) {
122 			init();
123 		}
124 		return stepMap.keySet();
125 	}
126 
127 	/**
128 	 * @see AbstractJob#doExecute(JobExecution)
129 	 */
130 	@Override
131 	protected void doExecute(final JobExecution execution) throws JobExecutionException {
132 		try {
133 			JobFlowExecutor executor = new JobFlowExecutor(getJobRepository(),
134 					new SimpleStepHandler(getJobRepository()), execution);
135 			executor.updateJobExecutionStatus(flow.start(executor).getStatus());
136 		}
137 		catch (FlowExecutionException e) {
138 			if (e.getCause() instanceof JobExecutionException) {
139 				throw (JobExecutionException) e.getCause();
140 			}
141 			throw new JobExecutionException("Flow execution ended unexpectedly", e);
142 		}
143 	}
144 
145 }