diff --git a/docs/src/site/docbook/reference/domain.xml b/docs/src/site/docbook/reference/domain.xml index d04a1bab8..d0d61bc6e 100644 --- a/docs/src/site/docbook/reference/domain.xml +++ b/docs/src/site/docbook/reference/domain.xml @@ -90,7 +90,7 @@ In Spring Batch, a Job is simply a continer for Steps. It combines multiple steps that belong logically together in a flow and allows for configuration of properties global to all steps, such as restartability. - The job configuration contains: + The job configuration contains: @@ -303,7 +303,7 @@ - JOB_INSTANCE_ID + JOB_INST_ID JOB_NAME @@ -323,7 +323,7 @@ - JOB_INSTANCE_ID + JOB_INST_ID TYPE_CD @@ -339,7 +339,7 @@ schedule.Date - 2008-01-01 00:00:00 + 2008-01-01 @@ -351,9 +351,9 @@ - JOB_EXECUTION_ID + JOB_EXEC_ID - JOB_INSTANCE_ID + JOB_INST_ID START_TIME @@ -367,9 +367,9 @@ 1 - 2008-01-01 21:00:23.571 + 2008-01-01 21:00 - 2008-01-01 21:30:17.132 + 2008-01-01 21:30 FAILED @@ -378,8 +378,8 @@ - extra columns in the tables have been removed for added - clarity. + column names may have been abbreviated or removed for clarity + and formatting Now that the job has failed, let's assume that it took the entire @@ -409,7 +409,7 @@ - JOB_INSTANCE_ID + JOB_INST_ID JOB_NAME @@ -435,7 +435,7 @@ - JOB_INSTANCE_ID + JOB_INST_ID TYPE_CD @@ -473,9 +473,9 @@ - JOB_EXECUTION_ID + JOB_EXEC_ID - JOB_INSTANCE_ID + JOB_INST_ID START_TIME @@ -522,6 +522,11 @@ + + + column names may have been abbreviated or removed for clarity + and formatting + @@ -717,7 +722,7 @@ - JOB_INSTANCE_ID + JOB_INST_ID JOB_NAME @@ -735,7 +740,7 @@ - JOB_INSTANCE_ID + JOB_INST_ID TYPE_CD @@ -751,7 +756,7 @@ schedule.Date - 2008-01-01 00:00:00 + 2008-01-01 @@ -761,9 +766,9 @@ - JOB_EXECUTION_ID + JOB_EXEC_ID - JOB_INSTANCE_ID + JOB_INST_ID START_TIME @@ -777,9 +782,9 @@ 1 - 2008-01-01 21:00:23.571 + 2008-01-01 21:00 - 2008-01-01 21:30:17.132 + 2008-01-01 21:30 FAILED @@ -791,9 +796,9 @@ - STEP_EXECUTION_ID + STEP_EXEC_ID - JOB_EXECUTION_ID + JOB_EXEC_ID STEP_NAME @@ -811,9 +816,9 @@ loadDate - 2008-01-01 21:00:23.571 + 2008-01-01 21:00 - 2008-01-01 21:30:17.132 + 2008-01-01 21:30 FAILED @@ -825,7 +830,7 @@ - STEP_EXECUTION_ID + STEP_EXEC_ID SHORT_CONTEXT @@ -945,8 +950,8 @@ public interface JobLauncher { - public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, - JobRestartException; + public JobExecution run(Job job, JobParameters jobParameters) + throws JobExecutionAlreadyRunningException, JobRestartException; } diff --git a/docs/src/site/docbook/reference/images/meta-data-erd.png b/docs/src/site/docbook/reference/images/meta-data-erd.png index 2a7179068..31771519e 100755 Binary files a/docs/src/site/docbook/reference/images/meta-data-erd.png and b/docs/src/site/docbook/reference/images/meta-data-erd.png differ diff --git a/docs/src/site/docbook/reference/job.xml b/docs/src/site/docbook/reference/job.xml index 92efd3f85..138fa6a91 100644 --- a/docs/src/site/docbook/reference/job.xml +++ b/docs/src/site/docbook/reference/job.xml @@ -154,11 +154,12 @@ void afterJob(JobExecution jobExecution){ - if( jobExecution.getStatus = BatchStatus.COMPLETED ){ - //job success - } - else if(jobExecution.getStatus = BatchStatus.FAILED){ - //job failure + if( jobExecution.getStatus = BatchStatus.COMPLETED ){ + //job success + } + else if(jobExecution.getStatus = BatchStatus.FAILED){ + //job failure + } } @@ -379,7 +380,8 @@ that you just don't need to persist status for a particular job. Spring batch provides a solution: - <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" /> + <bean id="jobRepository" + class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" /> diff --git a/docs/src/site/docbook/reference/readersAndWriters.xml b/docs/src/site/docbook/reference/readersAndWriters.xml index be82d6c85..c9bf6b77e 100644 --- a/docs/src/site/docbook/reference/readersAndWriters.xml +++ b/docs/src/site/docbook/reference/readersAndWriters.xml @@ -182,11 +182,14 @@ fields so that the fields may be accessed either by index or name as patterned after ResultSet: - String[] tokens = new String[]{"foo", "1", "true"}; + + String[] tokens = new String[]{"foo", "1", "true"}; FieldSet fs = new DefaultFieldSet(tokens); String name = fs.readString(0); int value = fs.readInt(1); - boolean booleanValue = fs.readBoolean(2); + boolean booleanValue = fs.readBoolean(2); + + There are many more options on the FieldSet interface, such as Date, long, @@ -217,7 +220,7 @@ guide will not go into the details of creating Resource objects. However, a simple example of a file system resource can be found below: - Resource resource = new FileSystemResource("resources/trades.csv"); + Resource resource = new FileSystemResource("resources/trades.csv"); In complex batch environments the directory structures are often @@ -320,10 +323,13 @@ As with RowMapper, which takes a low level construct such as ResultSet and returns an Object, flat file procesing requires the same construct to convert a String - line into an Object:public interface LineMapper<T> { + line into an Object: + public interface LineMapper<T> { - T mapLine(String line, int lineNumber) throws Exception; -} + T mapLine(String line, int lineNumber) throws Exception; + } + + The basic constract is that, given the current line, and the line number its associated with, return a resulting domain object. @@ -349,11 +355,14 @@ necessary. In Spring Batch, this is called a LineTokenizer: - public interface LineTokenizer { + + public interface LineTokenizer { FieldSet tokenize(String line); - } + } + + The contract of a LineTokenizer is such that, given a line of input (in theory the @@ -397,11 +406,14 @@ LineTokenizer to translate a line of data from a resource into an object of the desired type: - public interface FieldSetMapper<T> { + + public interface FieldSetMapper<T> { T mapFieldSet(FieldSet fieldSet); - } + } + + The pattern used is the same as RowMapper used by JdbcTemplate. @@ -459,7 +471,9 @@ public void setFieldSetMapper(FieldSetMapper<T> fieldSetMapper) { this.fieldSetMapper = fieldSetMapper; } -} + } + + The above functionality is provided in a default implementation, rather than being built into the reader itself (as was done in @@ -522,7 +536,8 @@ return player; } - } + } + The file can then be read by correctly constructing a FlatFileItemReader and calling @@ -583,7 +598,8 @@ return player; } - } + } +
@@ -599,14 +615,17 @@ FieldSetMapper configuration looks like the following: - <bean id="fieldSetMapper" + + <bean id="fieldSetMapper" class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"> <property name="prototypeBeanName" value="player" /> </bean> <bean id="player" class="org.springframework.batch.sample.domain.Player" - scope="prototype" /> + scope="prototype" /> + + For each entry in the FieldSet, the mapper will look for a corresponding setter on a new instance of the @@ -680,7 +699,8 @@ ApplicationContext: - <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> + <bean id="customEditorConfigurer" + class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="org.springframework.batch.item.file.transform.Range[]"> @@ -717,7 +737,8 @@ PrefixMatchingCompositeLineTokenizer makes this easier by matching the prefix in a line with a particular tokenizer: - <bean id="orderFileDescriptor" + + <bean id="orderFileDescriptor" class="org.springframework.batch.io.file.transform.PrefixMatchingCompositeLineTokenizer"> <property name="tokenizers"> <map> @@ -733,7 +754,9 @@ <entry key="" value-ref="defaultLineDescriptor" /> </map> </property> - </bean> + </bean> + + This ensures that the line will be parsed correctly, which is especially important for fixed length input. Any users of the @@ -863,11 +886,14 @@ writing to a file. In Spring Batch this is the LineAggregator: - public interface LineAggregator<T> { + + public interface LineAggregator<T> { public String aggregate(T item); - } + } + + The LineAggregator is the opposite of a LineTokenizer. @@ -927,20 +953,26 @@ FlatFileItemWriter expresses this in code: - public void write(T item) throws Exception { + + public void write(T item) throws Exception { write(lineAggregator.aggregate(item) + LINE_SEPARATOR); - } + } + + A simple configuration would look like the following: - <bean id="itemWriter" + + <bean id="itemWriter" class="org.springframework.batch.io.file.FlatFileItemWriter"> <property name="resource" value="file:target/test-outputs/20070122.testStream.multilineStep.txt" /> <property name="lineAggregator"> <bean class="org.springframework.batch.item.file.transform.PassThroughLineAggregator"/> </property> - </bean> + </bean> + +
@@ -1201,12 +1233,12 @@ + format="PNG" width="40%" /> + width="40%" /> Figure 3.1: XML Input @@ -1228,12 +1260,12 @@ + format="PNG" width="40%" /> + format="PNG" width="40%" /> Figure 3.2: OXM Binding @@ -2241,7 +2273,8 @@ <job id="ioSampleJob"> <step name="step1"> - <tasklet reader="fooReader" processor="fooProcessor" writer="compositeItemWriter" commit-interval="2"/> + <tasklet reader="fooReader" processor="fooProcessor" writer="compositeItemWriter" + commit-interval="2"/> <streams> <stream ref="barWriter" /> </streams> @@ -2357,11 +2390,14 @@ rather provides a very simple interface that can be implemented by any number of frameworks: - public interface Validator { + + public interface Validator { void validate(Object value) throws ValidationException; - } + } + + The contract is that the validate method will throw an exception if the object is invalid, and return normally if @@ -2381,9 +2417,14 @@ <value> <![CDATA[ { orderId : ? > 0 AND ? <= 9999999999 : 'Incorrect order ID' : 'error.order.id' } - { totalLines : ? = size(lineItems) : 'Bad count of order lines' : 'error.order.lines.badcount'} - { customer.registered : customer.businessCustomer = FALSE OR ? = TRUE : 'Business customer must be registered' : 'error.customer.registration'} - { customer.companyName : customer.businessCustomer = FALSE OR ? HAS TEXT : 'Company name for business customer is mandatory' :'error.customer.companyname'} + { totalLines : ? = size(lineItems) : 'Bad count of order lines' + : 'error.order.lines.badcount'} + { customer.registered : customer.businessCustomer = FALSE OR ? = TRUE + : 'Business customer must be registered' + : 'error.customer.registration'} + { customer.companyName : customer.businessCustomer = FALSE OR ? HAS TEXT + : 'Company name for business customer is mandatory' + :'error.customer.companyname'} ]]> </value> </property> @@ -2468,7 +2509,8 @@ basic contract of ItemReader, read: - public class CustomItemReader<T> implements ItemReader<T>{ + + public class CustomItemReader<T> implements ItemReader<T>{ List<T> items; @@ -2484,7 +2526,9 @@ } return null; } - } + } + + This very simple class takes a list of items, and returns one at a time, removing it from the list. When the list empty, it returns null, diff --git a/docs/src/site/docbook/reference/schema-appendix.xml b/docs/src/site/docbook/reference/schema-appendix.xml index ace579cfd..c7c1b28da 100644 --- a/docs/src/site/docbook/reference/schema-appendix.xml +++ b/docs/src/site/docbook/reference/schema-appendix.xml @@ -27,12 +27,14 @@ - + - + @@ -518,13 +520,13 @@ INSERT INTO BATCH_JOB_SEQ values(0); The framework will use the meta-data tables to determine if a particular JobInstance has been run before. If it has been run, and - the job is not restartable, then an exception will be thrown. + the job is not restartable, then an exception will be thrown. If an entry for a JobInstance is removed without having completed successfully, the framework will think that the job is new, - rather than a restart. + rather than a restart. @@ -536,4 +538,4 @@ INSERT INTO BATCH_JOB_SEQ values(0);
- + \ No newline at end of file diff --git a/docs/src/site/docbook/reference/step.xml b/docs/src/site/docbook/reference/step.xml index fc0b9df9e..95cd4cca9 100644 --- a/docs/src/site/docbook/reference/step.xml +++ b/docs/src/site/docbook/reference/step.xml @@ -204,8 +204,8 @@ <step name="step1"> - <tasklet reader="itemReader" writer="itemWriter" commit-interval="10" allow-start-if-complete="true"/> + <tasklet reader="itemReader" writer="itemWriter" commit-interval="10" + allow-start-if-complete="true"/> </step> @@ -484,7 +484,8 @@ </tasklet> </step> - <beans:bean id="compositeWriter" class="org.springframework.batch.item.support.CompositeItemWriter"> + <beans:bean id="compositeWriter" + class="org.springframework.batch.item.support.CompositeItemWriter"> <beans:property name="delegates"> <beans:list> <beans:ref bean="fileItemWriter1" /> @@ -972,13 +973,13 @@ + scale="" width="40%" /> + width="40%" /> @@ -1019,13 +1020,13 @@ rather than causing failure? + scale="" width="40%" /> + width="40%" /> @@ -1237,7 +1238,7 @@
- Creating File Names at Runtime + Late binding of Job and Step Attributes Both the XML and Flat File examples above use the Spring Resource abstraction to obtain the file to read @@ -1246,11 +1247,14 @@ java.io.File. Both XML and Flat File resources can be configured using standard Spring constructs: - <bean id="flatFileItemReader" + + <bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader"> <property name="resource" value="file://outputs/20070122.testStream.CustomerReportStep.TEMP.txt" /> - </bean> + </bean> + + The above Resource will load the file from the file system, at the location specificied. Note that absolute @@ -1260,10 +1264,13 @@ may need to be determined at runtime as a parameter to the job. This could be solved using '-D' parameters, i.e. a system property: - <bean id="flatFileItemReader" + + <bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader"> <property name="resource" value="${input.file.name}" /> -</bean> + </bean> + + All that would be required for this solution to work would be a system argument (-Dinput.file.name="file://file.txt"). (Note that @@ -1275,35 +1282,63 @@ Often in a batch setting it is preferable to parameterize the file name in the JobParameters of the job, instead of through system properties, and access them that way. To allow for this, - Spring Batch provides the - StepExecutionResourceProxy. The proxy can use - either job name, step name, or any values from the - JobParameters, by surrounding them with %: + Spring Batch allows for the late binding of various Job and Step + attributes: - <bean id="inputFile" - class="org.springframework.batch.core.resource.StepExecutionResourceProxy" /> - <property name="filePattern" value="//%JOB_NAME%/%STEP_NAME%/%file.name%" /> - </bean> + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{jobParameters[input.file.name]}" /> + </bean> - Assuming a job name of 'fooJob', and a step name of 'fooStep', and - the key-value pair of 'file.name="fileName.txt"' is in the - JobParameters the job is started with, the - following filename will be passed as the - Resource: - "//fooJob/fooStep/fileName.txt". It should be noted - that in order for the proxy to have access to the - StepExecution, it must be registered as a - StepListener: + - <bean id="fooStep" parent="abstractStep" - p:itemReader-ref="itemReader" - p:itemWriter-ref="itemWriter"> - <property name="listeners" ref="inputFile" /> - </bean> + Both the JobExecution and + StepExecution level + ExecutionContext can be access in the same + way: - The StepListener interface will be - discussed in more detail in Chapter 4. For now, it is sufficient to know - that the proxy must be registered. + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{jobExecutionContext[input.file.name]}" /> + </bean> + + + + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{stepExecutionContext[input.file.name]}" /> + </bean> + + + +
+ Step Scope + + All of the late binding examples from above have a scope of + "step" declared on the bean definition: + + + <bean id="flatFileItemReader" scope="step" + class="org.springframework.batch.item.file.FlatFileItemReader"> + <property name="resource" value="#{jobParameters[input.file.name]}" /> + </bean> + + + + Using a scope of Step is required in + order to use late binding, since the bean cannot actually be + instantiated until the Step starts, which + allows the attributes to be found. Because it is not part of the + Spring container by default, it must be added explicitely: + + + <bean class="org.springframework.batch.core.scope.StepScope" /> + + +
\ No newline at end of file