/* * Copyright 2013-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.batch.core.jsr.configuration.xml; import javax.batch.api.Batchlet; import javax.batch.api.chunk.CheckpointAlgorithm; import javax.batch.api.chunk.ItemProcessor; import javax.batch.api.chunk.ItemReader; import javax.batch.api.chunk.ItemWriter; import javax.batch.api.partition.PartitionReducer; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.xml.StepParserStepFactoryBean; import org.springframework.batch.core.jsr.configuration.support.BatchPropertyContext; import org.springframework.batch.core.jsr.partition.JsrPartitionHandler; import org.springframework.batch.core.jsr.step.batchlet.BatchletAdapter; import org.springframework.batch.core.jsr.step.builder.JsrBatchletStepBuilder; import org.springframework.batch.core.jsr.step.builder.JsrFaultTolerantStepBuilder; import org.springframework.batch.core.jsr.step.builder.JsrPartitionStepBuilder; import org.springframework.batch.core.jsr.step.builder.JsrSimpleStepBuilder; import org.springframework.batch.core.step.builder.FaultTolerantStepBuilder; import org.springframework.batch.core.step.builder.SimpleStepBuilder; import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.core.step.builder.TaskletStepBuilder; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.core.step.tasklet.TaskletStep; import org.springframework.batch.jsr.item.ItemProcessorAdapter; import org.springframework.batch.jsr.item.ItemReaderAdapter; import org.springframework.batch.jsr.item.ItemWriterAdapter; import org.springframework.batch.jsr.repeat.CheckpointAlgorithmAdapter; import org.springframework.batch.repeat.CompletionPolicy; import org.springframework.batch.repeat.policy.CompositeCompletionPolicy; import org.springframework.batch.repeat.policy.SimpleCompletionPolicy; import org.springframework.batch.repeat.policy.TimeoutTerminationPolicy; import org.springframework.beans.factory.FactoryBean; import org.springframework.util.Assert; /** * This {@link FactoryBean} is used by the JSR-352 namespace parser to create * {@link Step} objects. It stores all of the properties that are * configurable on the <step/>. * * @author Michael Minella * @author Chris Schaefer * @since 3.0 */ public class StepFactoryBean<I, O> extends StepParserStepFactoryBean<I, O> { @SuppressWarnings("unused") private int partitions; private BatchPropertyContext batchPropertyContext; private PartitionReducer reducer; private Integer timeout; public void setPartitionReducer(PartitionReducer reducer) { this.reducer = reducer; } public void setBatchPropertyContext(BatchPropertyContext context) { this.batchPropertyContext = context; } public void setPartitions(int partitions) { this.partitions = partitions; } /** * Create a {@link Step} from the configuration provided. * * @see FactoryBean#getObject() */ @Override public Step getObject() throws Exception { if(hasPartitionElement()) { return createPartitionStep(); } else if (hasChunkElement()) { Assert.isTrue(!hasTasklet(), "Step [" + getName() + "] has both a <chunk/> element and a 'ref' attribute referencing a Tasklet."); validateFaultTolerantSettings(); if (isFaultTolerant()) { return createFaultTolerantStep(); } else { return createSimpleStep(); } } else if (hasTasklet()) { return createTaskletStep(); } else { return createFlowStep(); } } /** * @return a new {@link TaskletStep} */ @Override protected TaskletStep createTaskletStep() { JsrBatchletStepBuilder jsrBatchletStepBuilder = new JsrBatchletStepBuilder(new StepBuilder(getName())); jsrBatchletStepBuilder.setBatchPropertyContext(batchPropertyContext); TaskletStepBuilder builder = jsrBatchletStepBuilder.tasklet(getTasklet()); enhanceTaskletStepBuilder(builder); return builder.build(); } @Override protected void setChunk(SimpleStepBuilder<I, O> builder) { if(timeout != null && getCommitInterval() != null) { CompositeCompletionPolicy completionPolicy = new CompositeCompletionPolicy(); CompletionPolicy [] policies = new CompletionPolicy[2]; policies[0] = new SimpleCompletionPolicy(getCommitInterval()); policies[1] = new TimeoutTerminationPolicy(timeout * 1000); completionPolicy.setPolicies(policies); builder.chunk(completionPolicy); } else if(timeout != null) { builder.chunk(new TimeoutTerminationPolicy(timeout * 1000)); } else if(getCommitInterval() != null) { builder.chunk(getCommitInterval()); } if(getCompletionPolicy() != null) { builder.chunk(getCompletionPolicy()); } } @Override protected Step createPartitionStep() { // Creating a partitioned step for the JSR needs to create two steps...the partitioned step and the step being executed. Step executedStep = null; if (hasChunkElement()) { Assert.isTrue(!hasTasklet(), "Step [" + getName() + "] has both a <chunk/> element and a 'ref' attribute referencing a Tasklet."); validateFaultTolerantSettings(); if (isFaultTolerant()) { executedStep = createFaultTolerantStep(); } else { executedStep = createSimpleStep(); } } else if (hasTasklet()) { executedStep = createTaskletStep(); } ((JsrPartitionHandler) super.getPartitionHandler()).setStep(executedStep); JsrPartitionStepBuilder builder = new JsrSimpleStepBuilder<I, O>(new StepBuilder(executedStep.getName())).partitioner(executedStep); enhanceCommonStep(builder); if (getPartitionHandler() != null) { builder.partitionHandler(getPartitionHandler()); } if(reducer != null) { builder.reducer(reducer); } builder.aggregator(getStepExecutionAggergator()); return builder.build(); } /** * Wraps a {@link Batchlet} in a {@link BatchletAdapter} if required for consumption * by the rest of the framework. * * @param tasklet {@link Tasklet} or {@link Batchlet} implementation * @throws IllegalArgumentException if tasklet does not implement either Tasklet or Batchlet */ public void setStepTasklet(Object tasklet) { if(tasklet instanceof Tasklet) { super.setTasklet((Tasklet) tasklet); } else if(tasklet instanceof Batchlet){ super.setTasklet(new BatchletAdapter((Batchlet) tasklet)); } else { throw new IllegalArgumentException("The field tasklet must reference an implementation of " + "either org.springframework.batch.core.step.tasklet.Tasklet or javax.batch.api.Batchlet"); } } /** * Wraps a {@link ItemReader} in a {@link ItemReaderAdapter} if required for consumption * by the rest of the framework. * * @param itemReader {@link ItemReader} or {@link org.springframework.batch.item.ItemReader} implementation * @throws IllegalArgumentException if itemReader does not implement either version of ItemReader */ @SuppressWarnings("unchecked") public void setStepItemReader(Object itemReader) { if(itemReader instanceof org.springframework.batch.item.ItemReader) { super.setItemReader((org.springframework.batch.item.ItemReader<I>) itemReader); } else if(itemReader instanceof ItemReader){ super.setItemReader(new ItemReaderAdapter<I>((ItemReader) itemReader)); } else { throw new IllegalArgumentException("The definition of an item reader must implement either " + "org.springframework.batch.item.ItemReader or javax.batch.api.chunk.ItemReader"); } } /** * Wraps a {@link ItemProcessor} in a {@link ItemProcessorAdapter} if required for consumption * by the rest of the framework. * * @param itemProcessor {@link ItemProcessor} or {@link org.springframework.batch.item.ItemProcessor} implementation * @throws IllegalArgumentException if itemProcessor does not implement either version of ItemProcessor */ @SuppressWarnings("unchecked") public void setStepItemProcessor(Object itemProcessor) { if(itemProcessor instanceof org.springframework.batch.item.ItemProcessor) { super.setItemProcessor((org.springframework.batch.item.ItemProcessor<I, O>) itemProcessor); } else if(itemProcessor instanceof ItemProcessor){ super.setItemProcessor(new ItemProcessorAdapter<I, O>((ItemProcessor)itemProcessor)); } else { throw new IllegalArgumentException("The definition of an item processor must implement either " + "org.springframework.batch.item.ItemProcessor or javax.batch.api.chunk.ItemProcessor"); } } /** * Wraps a {@link ItemWriter} in a {@link ItemWriterAdapter} if required for consumption * by the rest of the framework. * * @param itemWriter {@link ItemWriter} or {@link org.springframework.batch.item.ItemWriter} implementation * @throws IllegalArgumentException if itemWriter does not implement either version of ItemWriter */ @SuppressWarnings("unchecked") public void setStepItemWriter(Object itemWriter) { if(itemWriter instanceof org.springframework.batch.item.ItemWriter) { super.setItemWriter((org.springframework.batch.item.ItemWriter<O>) itemWriter); } else if(itemWriter instanceof ItemWriter){ super.setItemWriter(new ItemWriterAdapter<O>((ItemWriter) itemWriter)); } else { throw new IllegalArgumentException("The definition of an item writer must implement either " + "org.springframework.batch.item.ItemWriter or javax.batch.api.chunk.ItemWriter"); } } /** * Wraps a {@link CheckpointAlgorithm} in a {@link CheckpointAlgorithmAdapter} if required for consumption * by the rest of the framework. * * @param chunkCompletionPolicy {@link CompletionPolicy} or {@link CheckpointAlgorithm} implementation * @throws IllegalArgumentException if chunkCompletionPolicy does not implement either CompletionPolicy or CheckpointAlgorithm */ public void setStepChunkCompletionPolicy(Object chunkCompletionPolicy) { if(chunkCompletionPolicy instanceof CompletionPolicy) { super.setChunkCompletionPolicy((CompletionPolicy) chunkCompletionPolicy); } else if(chunkCompletionPolicy instanceof CheckpointAlgorithm) { super.setChunkCompletionPolicy(new CheckpointAlgorithmAdapter((CheckpointAlgorithm) chunkCompletionPolicy)); } else { throw new IllegalArgumentException("The definition of a chunk completion policy must implement either " + "org.springframework.batch.repeat.CompletionPolicy or javax.batch.api.chunk.CheckpointAlgorithm"); } } @Override protected FaultTolerantStepBuilder<I, O> getFaultTolerantStepBuilder(String stepName) { JsrFaultTolerantStepBuilder<I, O> jsrFaultTolerantStepBuilder = new JsrFaultTolerantStepBuilder<I, O>(new StepBuilder(stepName)); jsrFaultTolerantStepBuilder.setBatchPropertyContext(batchPropertyContext); return jsrFaultTolerantStepBuilder; } @Override protected SimpleStepBuilder<I, O> getSimpleStepBuilder(String stepName) { JsrSimpleStepBuilder<I, O> jsrSimpleStepBuilder = new JsrSimpleStepBuilder<I, O>(new StepBuilder(stepName)); jsrSimpleStepBuilder.setBatchPropertyContext(batchPropertyContext); return jsrSimpleStepBuilder; } public void setTimeout(Integer timeout) { this.timeout = timeout; } }