diff --git a/spring-batch-core-tests/pom.xml b/spring-batch-core-tests/pom.xml index 34b95f850..67f418a9d 100644 --- a/spring-batch-core-tests/pom.xml +++ b/spring-batch-core-tests/pom.xml @@ -152,11 +152,6 @@ cglib-nodep true - - com.ibm.jbatch - com.ibm.jbatch-tck-spi - 1.0-b28 - diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index b3f2dc01d..2b8268cfa 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -23,6 +23,11 @@ javax.batch-api 1.0-b29 + + com.ibm.jbatch + com.ibm.jbatch-tck-spi + 1.0 + org.hsqldb hsqldb @@ -204,7 +209,7 @@ - + diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/BatchStatus.java b/spring-batch-core/src/main/java/org/springframework/batch/core/BatchStatus.java index 15e2414dc..ff158edc3 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/BatchStatus.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/BatchStatus.java @@ -21,6 +21,7 @@ package org.springframework.batch.core; * * @author Lucas Ward * @author Dave Syer + * @author Michael Minella */ public enum BatchStatus { @@ -76,8 +77,9 @@ public enum BatchStatus { return max(this, other); } // Both less than or equal to STARTED - if (this == COMPLETED || other == COMPLETED) + if (this == COMPLETED || other == COMPLETED) { return COMPLETED; + } return max(this, other); } @@ -105,6 +107,29 @@ public enum BatchStatus { return this.compareTo(other) <= 0; } + /** + * Converts the current status to the JSR-352 equivalent + * + * @return JSR-352 equivalent to the current status + */ + public javax.batch.runtime.BatchStatus getBatchStatus() { + if(this == ABANDONED) { + return javax.batch.runtime.BatchStatus.ABANDONED; + } else if(this == COMPLETED) { + return javax.batch.runtime.BatchStatus.COMPLETED; + } else if(this == STARTED) { + return javax.batch.runtime.BatchStatus.STARTED; + } else if(this == STARTING) { + return javax.batch.runtime.BatchStatus.STARTING; + } else if(this == STOPPED) { + return javax.batch.runtime.BatchStatus.STOPPED; + } else if(this == STOPPING) { + return javax.batch.runtime.BatchStatus.STOPPING; + } else { + return javax.batch.runtime.BatchStatus.FAILED; + } + } + /** * Find a BatchStatus that matches the beginning of the given value. If no * match is found, return COMPLETED as the default because has is low diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobInstance.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobInstance.java index dfe83d5fe..54f04cb1d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobInstance.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobInstance.java @@ -30,6 +30,7 @@ import org.springframework.util.Assert; * @see Job * @see JobParameters * @see JobExecution + * @see javax.batch.runtime.JobInstance * * @author Lucas Ward * @author Dave Syer @@ -38,7 +39,7 @@ import org.springframework.util.Assert; * */ @SuppressWarnings("serial") -public class JobInstance extends Entity { +public class JobInstance extends Entity implements javax.batch.runtime.JobInstance{ private final String jobName; @@ -51,6 +52,7 @@ public class JobInstance extends Entity { /** * @return the job name. (Equivalent to getJob().getName()) */ + @Override public String getJobName() { return jobName; } @@ -60,4 +62,8 @@ public class JobInstance extends Entity { return super.toString() + ", Job=[" + jobName + "]"; } + @Override + public long getInstanceId() { + return super.getId(); + } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java index e62ba71c1..5a7231baa 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java @@ -20,6 +20,7 @@ import java.io.Serializable; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; /** * Value object representing runtime parameters to a batch job. Because the @@ -209,4 +210,16 @@ public class JobParameters implements Serializable { public String toString() { return parameters.toString(); } + + public Properties toProperties() { + Properties props = new Properties(); + + for (Map.Entry param : parameters.entrySet()) { + if(param.getValue() != null) { + props.put(param.getKey(), param.getValue().toString()); + } + } + + return props; + } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java index e4e5de7a5..6939f6625 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java @@ -19,6 +19,7 @@ package org.springframework.batch.core; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; import org.springframework.util.Assert; @@ -58,6 +59,22 @@ public class JobParametersBuilder { this.parameterMap = new LinkedHashMap(jobParameters.getParameters()); } + /** + * Constructor to add conversion capabilities to support JSR-352. Per the spec, it is expected that all + * keys and values in the provided {@link Properties} instance are Strings + * + * @param properties the job parameters to be used + */ + public JobParametersBuilder(Properties properties) { + this.parameterMap = new LinkedHashMap(); + + if(properties != null) { + for (Map.Entry curProperty : properties.entrySet()) { + this.parameterMap.put((String) curProperty.getKey(), new JobParameter((String) curProperty.getValue(), false)); + } + } + } + /** * Add a new identifying String parameter for the given key. * diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBean.java index b3a28f128..a48d4be9a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBean.java @@ -33,6 +33,11 @@ import org.springframework.batch.core.Step; import org.springframework.batch.core.StepExecutionListener; import org.springframework.batch.core.StepListener; import org.springframework.batch.core.job.flow.Flow; +import org.springframework.batch.core.jsr.ChunkListenerAdapter; +import org.springframework.batch.core.jsr.ItemProcessListenerAdapter; +import org.springframework.batch.core.jsr.ItemReadListenerAdapter; +import org.springframework.batch.core.jsr.ItemWriteListenerAdapter; +import org.springframework.batch.core.jsr.StepListenerAdapter; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.partition.PartitionHandler; import org.springframework.batch.core.partition.support.Partitioner; @@ -85,6 +90,7 @@ import org.springframework.util.Assert; * * @author Dan Garrette * @author Josh Long + * @author Michael Minella * @see SimpleStepFactoryBean * @see FaultTolerantStepFactoryBean * @see TaskletStep @@ -111,7 +117,7 @@ public class StepParserStepFactoryBean implements FactoryBean, BeanNameAwa private PlatformTransactionManager transactionManager; - private Set stepExecutionListeners = new LinkedHashSet(); + private Set stepExecutionListeners = new LinkedHashSet(); // // Flow Elements @@ -218,8 +224,6 @@ public class StepParserStepFactoryBean implements FactoryBean, BeanNameAwa private StepExecutionAggregator stepExecutionAggregator; - private StepListener[] listeners; - /** * Create a {@link Step} from the configuration provided. * @@ -269,8 +273,12 @@ public class StepParserStepFactoryBean implements FactoryBean, BeanNameAwa } builder.repository(jobRepository); builder.transactionManager(transactionManager); - for (StepExecutionListener listener : stepExecutionListeners) { - builder.listener(listener); + for (Object listener : stepExecutionListeners) { + if(listener instanceof StepExecutionListener) { + builder.listener((StepExecutionListener) listener); + } else if(listener instanceof StepListener) { + builder.listener(new StepListenerAdapter((javax.batch.api.listener.StepListener) listener)); + } } } @@ -715,11 +723,11 @@ public class StepParserStepFactoryBean implements FactoryBean, BeanNameAwa * * @param listeners an array of listeners */ - public void setListeners(StepListener[] listeners) { - this.listeners = listeners; // useful for testing - for (StepListener listener : listeners) { + @SuppressWarnings("unchecked") + public void setListeners(Object[] listeners) { + // this.listeners = listeners; // useful for testing + for (Object listener : listeners) { if (listener instanceof SkipListener) { - @SuppressWarnings("unchecked") SkipListener skipListener = (SkipListener) listener; skipListeners.add(skipListener); } @@ -727,25 +735,42 @@ public class StepParserStepFactoryBean implements FactoryBean, BeanNameAwa StepExecutionListener stepExecutionListener = (StepExecutionListener) listener; stepExecutionListeners.add(stepExecutionListener); } + if(listener instanceof javax.batch.api.listener.StepListener) { + StepExecutionListener stepExecutionListener = new StepListenerAdapter((javax.batch.api.listener.StepListener) listener); + stepExecutionListeners.add(stepExecutionListener); + } if (listener instanceof ChunkListener) { ChunkListener chunkListener = (ChunkListener) listener; chunkListeners.add(chunkListener); } + if(listener instanceof javax.batch.api.chunk.listener.ChunkListener) { + ChunkListener chunkListener = new ChunkListenerAdapter((javax.batch.api.chunk.listener.ChunkListener) listener); + chunkListeners.add(chunkListener); + } if (listener instanceof ItemReadListener) { - @SuppressWarnings("unchecked") ItemReadListener readListener = (ItemReadListener) listener; readListeners.add(readListener); } + if(listener instanceof javax.batch.api.chunk.listener.ItemReadListener) { + ItemReadListener itemListener = new ItemReadListenerAdapter((javax.batch.api.chunk.listener.ItemReadListener) listener); + readListeners.add(itemListener); + } if (listener instanceof ItemWriteListener) { - @SuppressWarnings("unchecked") ItemWriteListener writeListener = (ItemWriteListener) listener; writeListeners.add(writeListener); } + if(listener instanceof javax.batch.api.chunk.listener.ItemWriteListener) { + ItemWriteListener itemListener = new ItemWriteListenerAdapter((javax.batch.api.chunk.listener.ItemWriteListener) listener); + writeListeners.add(itemListener); + } if (listener instanceof ItemProcessListener) { - @SuppressWarnings("unchecked") ItemProcessListener processListener = (ItemProcessListener) listener; processListeners.add(processListener); } + if(listener instanceof javax.batch.api.chunk.listener.ItemProcessListener) { + ItemProcessListener itemListener = new ItemProcessListenerAdapter((javax.batch.api.chunk.listener.ItemProcessListener) listener); + processListeners.add(itemListener); + } } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ChunkListenerAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ChunkListenerAdapter.java new file mode 100644 index 000000000..68e902422 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ChunkListenerAdapter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013 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; + +import javax.batch.operations.BatchRuntimeException; + +import org.springframework.batch.core.ChunkListener; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.util.Assert; + +/** + * Wrapper class to adapt the {@link javax.batch.api.chunk.listener.ChunkListener} to + * a {@link ChunkListener}. + * + * @author Michael Minella + * @since 3.0 + */ +public class ChunkListenerAdapter implements ChunkListener { + + private final javax.batch.api.chunk.listener.ChunkListener delegate; + + /** + * @param delegate to be called within the step chunk lifecycle + */ + public ChunkListenerAdapter(javax.batch.api.chunk.listener.ChunkListener delegate) { + Assert.notNull(delegate, "A ChunkListener is required"); + this.delegate = delegate; + } + + @Override + public void beforeChunk(ChunkContext context) { + try { + delegate.beforeChunk(); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void afterChunk(ChunkContext context) { + try { + delegate.afterChunk(); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void afterChunkError(ChunkContext context) { + if(context != null) { + try { + delegate.onError((Exception) context.getAttribute(ChunkListener.ROLLBACK_EXCEPTION_KEY)); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } else { + throw new BatchRuntimeException("Unable to retrieve causing exception"); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemProcessListenerAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemProcessListenerAdapter.java new file mode 100644 index 000000000..ac031de69 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemProcessListenerAdapter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2013 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; + +import javax.batch.operations.BatchRuntimeException; + +import org.springframework.batch.core.ItemProcessListener; +import org.springframework.util.Assert; + +/** + * Wrapper class for {@link javax.batch.api.chunk.listener.ItemProcessListener} + * + * @author Michael Minella + * + * @param input type + * @param output type + * @since 3.0 + */ +public class ItemProcessListenerAdapter implements ItemProcessListener { + + private javax.batch.api.chunk.listener.ItemProcessListener delegate; + + /** + * @param delegate to be called within the batch lifecycle + */ + public ItemProcessListenerAdapter(javax.batch.api.chunk.listener.ItemProcessListener delegate) { + Assert.notNull(delegate, "An ItemProcessListener is requred"); + this.delegate = delegate; + } + + @Override + public void beforeProcess(T item) { + try { + delegate.beforeProcess(item); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void afterProcess(T item, S result) { + try { + delegate.afterProcess(item, result); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void onProcessError(T item, Exception e) { + try { + delegate.onProcessError(item, e); + } catch (Exception e1) { + throw new BatchRuntimeException(e); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemReadListenerAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemReadListenerAdapter.java new file mode 100644 index 000000000..e5f1a08f1 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemReadListenerAdapter.java @@ -0,0 +1,68 @@ +/* + * Copyright 2013 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; + +import javax.batch.operations.BatchRuntimeException; + +import org.springframework.batch.core.ItemReadListener; +import org.springframework.batch.item.ItemReader; +import org.springframework.util.Assert; + +/** + * Wrapper class to adapt the {@link javax.batch.api.chunk.listener.ItemReadListener} to + * a {@link ItemReadListener}. + * + * @author Michael Minella + * + * @param type to be returned via a read on the associated {@link ItemReader} + * @since 3.0 + */ +public class ItemReadListenerAdapter implements ItemReadListener { + + private javax.batch.api.chunk.listener.ItemReadListener delegate; + + public ItemReadListenerAdapter(javax.batch.api.chunk.listener.ItemReadListener delegate) { + Assert.notNull(delegate, "An ItemReadListener is required"); + this.delegate = delegate; + } + + @Override + public void beforeRead() { + try { + delegate.beforeRead(); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void afterRead(T item) { + try { + delegate.afterRead(item); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void onReadError(Exception ex) { + try { + delegate.onReadError(ex); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemWriteListenerAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemWriteListenerAdapter.java new file mode 100644 index 000000000..abe4c48f4 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/ItemWriteListenerAdapter.java @@ -0,0 +1,71 @@ +/* + * Copyright 2013 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; + +import java.util.List; + +import javax.batch.operations.BatchRuntimeException; + +import org.springframework.batch.core.ItemWriteListener; +import org.springframework.batch.item.ItemWriter; +import org.springframework.util.Assert; + +/** + * Wrapper class to adapt the {@link javax.batch.api.chunk.listener.ItemWriteListener} to + * a {@link ItemWriteListener}. + * + * @author Michael Minella + * + * @param type to be written by the associated {@link ItemWriter} + * @since 3.0 + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class ItemWriteListenerAdapter implements ItemWriteListener { + + private javax.batch.api.chunk.listener.ItemWriteListener delegate; + + public ItemWriteListenerAdapter(javax.batch.api.chunk.listener.ItemWriteListener delegate) { + Assert.notNull(delegate, "An ItemWriteListener is required"); + this.delegate = delegate; + } + + @Override + public void beforeWrite(List items) { + try { + delegate.beforeWrite(items); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void afterWrite(List items) { + try { + delegate.afterWrite(items); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void onWriteError(Exception exception, List items) { + try { + delegate.onWriteError(items, exception); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobContext.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobContext.java new file mode 100644 index 000000000..bb2b79827 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobContext.java @@ -0,0 +1,92 @@ +/* + * Copyright 2013 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; + +import java.util.Properties; + +import javax.batch.runtime.BatchStatus; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.util.Assert; + +/** + * Wrapper class to provide the {@link javax.batch.runtime.context.JobContext} functionality + * as specified in JSR-352. Wrapper delegates to the underlying {@link JobExecution} to + * obtain the related contextual information. + * + * @author Michael Minella + * @since 3.0 + */ +public class JobContext implements javax.batch.runtime.context.JobContext { + + private JobExecution jobExecution; + private Object transientUserData; + + /** + * @param jobExecution for the related job + */ + public JobContext(JobExecution jobExecution) { + Assert.notNull(jobExecution, "A JobExecution is required"); + + this.jobExecution = jobExecution; + } + + @Override + public String getJobName() { + return jobExecution.getJobInstance().getJobName(); + } + + @Override + public Object getTransientUserData() { + return transientUserData; + } + + @Override + public void setTransientUserData(Object data) { + transientUserData = data; + } + + @Override + public long getInstanceId() { + return jobExecution.getJobInstance().getId(); + } + + @Override + public long getExecutionId() { + return jobExecution.getId(); + } + + @Override + public Properties getProperties() { + return jobExecution.getJobParameters().toProperties(); + } + + @Override + public BatchStatus getBatchStatus() { + return jobExecution.getStatus().getBatchStatus(); + } + + @Override + public String getExitStatus() { + return jobExecution.getExitStatus().getExitCode(); + } + + @Override + public void setExitStatus(String status) { + jobExecution.setExitStatus(new ExitStatus(status)); + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobExecution.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobExecution.java new file mode 100644 index 000000000..b489a30cf --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobExecution.java @@ -0,0 +1,88 @@ +/* + * Copyright 2013 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; + +import java.util.Date; +import java.util.Properties; + +import javax.batch.runtime.BatchStatus; + +import org.springframework.util.Assert; + +/** + * Wrapper class to adapt the {@link javax.batch.runtime.JobExecution} to + * a {@link JobExecution}. + * + * @author Michael Minella + * @since 3.0 + */ +public class JobExecution implements javax.batch.runtime.JobExecution { + + private org.springframework.batch.core.JobExecution execution; + + /** + * @param execution for all information to be delegated from + */ + public JobExecution(org.springframework.batch.core.JobExecution execution) { + Assert.notNull(execution, "A JobExecution is required"); + this.execution = execution; + } + + @Override + public long getExecutionId() { + return this.execution.getId(); + } + + @Override + public String getJobName() { + return this.execution.getJobInstance().getJobName(); + } + + @Override + public BatchStatus getBatchStatus() { + return this.execution.getStatus().getBatchStatus(); + } + + @Override + public Date getStartTime() { + return this.execution.getStartTime(); + } + + @Override + public Date getEndTime() { + return this.execution.getEndTime(); + } + + @Override + public String getExitStatus() { + return this.execution.getExitStatus().getExitCode(); + } + + @Override + public Date getCreateTime() { + return this.execution.getCreateTime(); + } + + @Override + public Date getLastUpdatedTime() { + return this.execution.getLastUpdated(); + } + + @Override + public Properties getJobParameters() { + return this.execution.getJobParameters().toProperties(); + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobListenerAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobListenerAdapter.java new file mode 100644 index 000000000..afdadeb29 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JobListenerAdapter.java @@ -0,0 +1,61 @@ +/* + * Copyright 2013 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; + +import javax.batch.api.listener.JobListener; +import javax.batch.operations.BatchRuntimeException; + +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobExecutionListener; +import org.springframework.util.Assert; + +/** + * Wrapper class to adapt the {@link JobListener} to + * a {@link JobExecutionListener}. + * + * @author Michael Minella + * @since 3.0 + */ +public class JobListenerAdapter implements JobExecutionListener { + + private JobListener delegate; + + /** + * @param delegate to be delegated to + */ + public JobListenerAdapter(JobListener delegate) { + Assert.notNull(delegate); + this.delegate = delegate; + } + + @Override + public void beforeJob(JobExecution jobExecution) { + try { + delegate.beforeJob(); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public void afterJob(JobExecution jobExecution) { + try { + delegate.afterJob(); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JsrJobListenerMetaData.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JsrJobListenerMetaData.java new file mode 100644 index 000000000..99dd95141 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JsrJobListenerMetaData.java @@ -0,0 +1,89 @@ +/* + * Copyright 2013 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; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; + +import javax.batch.api.listener.JobListener; + +import org.springframework.batch.core.listener.ListenerMetaData; + +/** + * Enumeration for {@link JobListener} meta data, which ties together the names + * of methods, their interfaces, annotation, and expected arguments. + * + * @author Michael Minella + * @since 3.0 + */ +public enum JsrJobListenerMetaData implements ListenerMetaData { + BEFORE_JOB("beforeJob", "jsr-before-job", null), + AFTER_JOB("afterJob", "jsr-after-job", null); + + private final String methodName; + private final String propertyName; + private final Class annotation; + private static final Map propertyMap; + + JsrJobListenerMetaData(String methodName, String propertyName, Class annotation) { + this.methodName = methodName; + this.propertyName = propertyName; + this.annotation = annotation; + } + + static{ + propertyMap = new HashMap(); + for(JsrJobListenerMetaData metaData : values()){ + propertyMap.put(metaData.getPropertyName(), metaData); + } + } + + @Override + public String getMethodName() { + return methodName; + } + + @Override + public Class getAnnotation() { + return annotation; + } + + @Override + public Class getListenerInterface() { + return JobListener.class; + } + + @Override + public String getPropertyName() { + return propertyName; + } + + @Override + public Class[] getParamTypes() { + return new Class[0]; + } + + /** + * Return the relevant meta data for the provided property name. + * + * @param propertyName + * @return meta data with supplied property name, null if none exists. + */ + public static JsrJobListenerMetaData fromPropertyName(String propertyName){ + return propertyMap.get(propertyName); + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JsrStepListenerMetaData.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JsrStepListenerMetaData.java new file mode 100644 index 000000000..d0a373999 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/JsrStepListenerMetaData.java @@ -0,0 +1,112 @@ +/* + * Copyright 2013 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; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.batch.api.chunk.listener.ChunkListener; +import javax.batch.api.chunk.listener.ItemProcessListener; +import javax.batch.api.chunk.listener.ItemReadListener; +import javax.batch.api.chunk.listener.ItemWriteListener; +import javax.batch.api.listener.StepListener; + +import org.springframework.batch.core.listener.ListenerMetaData; +import org.springframework.batch.core.listener.StepListenerFactoryBean; + +/** + * Enumeration for the JSR specific {@link StepListener} meta data, which + * ties together the names of methods, their interfaces, and expected arguments. + * + * @author Michael Minella + * @since 3.0 + * @see StepListenerFactoryBean + */ +public enum JsrStepListenerMetaData implements ListenerMetaData { + + BEFORE_STEP("beforeStep", "jsr-before-step", StepListener.class), + AFTER_STEP("afterStep", "jsr-after-step", StepListener.class), + BEFORE_CHUNK("beforeChunk", "jsr-before-chunk", ChunkListener.class), + AFTER_CHUNK("afterChunk", "jsr-after-chunk", ChunkListener.class), + AFTER_CHUNK_ERROR("onError", "jsr-after-chunk-error", ChunkListener.class, Exception.class), + BEFORE_READ("beforeRead", "jsr-before-read", ItemReadListener.class), + AFTER_READ("afterRead", "jsr-after-read", ItemReadListener.class, Object.class), + AFTER_READ_ERROR("onReadError", "jsr-after-read-error", ItemReadListener.class, Exception.class), + BEFORE_PROCESS("beforeProcess", "jsr-before-process", ItemProcessListener.class, Object.class), + AFTER_PROCESS("afterProcess", "jsr-after-process", ItemProcessListener.class, Object.class, Object.class), + AFTER_PROCESS_ERROR("onProcessError", "jsr-after-process-error", ItemProcessListener.class, Object.class, Exception.class), + BEFORE_WRITE("beforeWrite", "jsr-before-write", ItemWriteListener.class, List.class), + AFTER_WRITE("afterWrite", "jsr-after-write", ItemWriteListener.class, List.class), + AFTER_WRITE_ERROR("onWriteError", "jsr-after-write-error", ItemWriteListener.class, List.class, Exception.class); + + private final String methodName; + private final String propertyName; + private final Class listenerInterface; + private static final Map propertyMap; + private final Class[] paramTypes; + + @SuppressWarnings({"rawtypes", "unchecked"}) + JsrStepListenerMetaData(String methodName, String propertyName, Class listenerInterface, Class... paramTypes) { + this.propertyName = propertyName; + this.methodName = methodName; + this.listenerInterface = listenerInterface; + this.paramTypes = paramTypes; + } + + static{ + propertyMap = new HashMap(); + for(JsrStepListenerMetaData metaData : values()){ + propertyMap.put(metaData.getPropertyName(), metaData); + } + } + + @Override + public String getMethodName() { + return methodName; + } + + @Override + public Class getAnnotation() { + return null; + } + + @Override + public Class getListenerInterface() { + return listenerInterface; + } + + @Override + public Class[] getParamTypes() { + return paramTypes; + } + + @Override + public String getPropertyName() { + return propertyName; + } + + /** + * Return the relevant meta data for the provided property name. + * + * @param propertyName + * @return meta data with supplied property name, null if none exists. + */ + public static JsrStepListenerMetaData fromPropertyName(String propertyName){ + return propertyMap.get(propertyName); + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/SkipListenerAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/SkipListenerAdapter.java new file mode 100644 index 000000000..60904a0c7 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/SkipListenerAdapter.java @@ -0,0 +1,47 @@ +package org.springframework.batch.core.jsr; + +import javax.batch.api.chunk.listener.SkipProcessListener; +import javax.batch.api.chunk.listener.SkipReadListener; +import javax.batch.api.chunk.listener.SkipWriteListener; + +import org.springframework.batch.core.SkipListener; + +public class SkipListenerAdapter implements SkipListener { + + private final SkipReadListener skipReadDelegate; + private final SkipProcessListener skipProcessDelegate; + private final SkipWriteListener skipWriteDelegate; + + public SkipListenerAdapter(SkipReadListener skipReadDelgate, SkipProcessListener skipProcessDelegate, SkipWriteListener skipWriteDelegate) { + this.skipReadDelegate = skipReadDelgate; + this.skipProcessDelegate = skipProcessDelegate; + this.skipWriteDelegate = skipWriteDelegate; + } + + @Override + public void onSkipInRead(Throwable t) { + if(skipReadDelegate != null && t instanceof Exception) { + try { + skipReadDelegate.onSkipReadItem((Exception) t); + } catch (Exception e) { + //TODO: Do something here + } + } + } + + @Override + public void onSkipInWrite(S item, Throwable t) { + //TODO: Awating information on the JSR's method + } + + @Override + public void onSkipInProcess(T item, Throwable t) { + if(skipProcessDelegate != null && t instanceof Exception) { + try { + skipProcessDelegate.onSkipProcessItem(item, (Exception) t); + } catch (Exception e) { + //TODO: Do something here + } + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/StepListenerAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/StepListenerAdapter.java new file mode 100644 index 000000000..6fa80407f --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/StepListenerAdapter.java @@ -0,0 +1,64 @@ +/* + * Copyright 2013 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; + +import javax.batch.api.listener.StepListener; +import javax.batch.operations.BatchRuntimeException; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.StepExecutionListener; +import org.springframework.util.Assert; + +/** + * Wrapper class to adapt the {@link StepListener} to + * a {@link StepExecutionListener}. + * + * @author Michael Minella + * @since 3.0 + */ +public class StepListenerAdapter implements StepExecutionListener { + + private final StepListener delegate; + + /** + * @param delegate + */ + public StepListenerAdapter(StepListener delegate) { + Assert.notNull(delegate, "A listener is required"); + this.delegate = delegate; + } + + @Override + public void beforeStep(StepExecution stepExecution) { + try { + delegate.beforeStep(); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + } + + @Override + public ExitStatus afterStep(StepExecution stepExecution) { + try { + delegate.afterStep(); + } catch (Exception e) { + throw new BatchRuntimeException(e); + } + + return stepExecution.getExitStatus(); + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchParser.java index 1cb20ffa2..c76faa164 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchParser.java @@ -64,6 +64,8 @@ public class BatchParser extends AbstractBeanDefinitionParser { AbstractBeanDefinition beanDefintion = BeanDefinitionBuilder.genericBeanDefinition(curElement.getAttribute("class")) .getBeanDefinition(); + beanDefintion.setScope("step"); + String beanName = curElement.getAttribute("id"); if(!registry.containsBeanDefinition(beanName)) { diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchletParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchletParser.java index a05549c3c..a906a897f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchletParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/BatchletParser.java @@ -15,7 +15,6 @@ */ package org.springframework.batch.core.jsr.configuration.xml; -import org.springframework.batch.core.configuration.xml.StepParserStepFactoryBean; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; @@ -40,8 +39,8 @@ public class BatchletParser extends AbstractSingleBeanDefinitionParser { public void parseBatchlet(Element stepElement, Element taskletElement, AbstractBeanDefinition bd, ParserContext parserContext) { - bd.setBeanClass(StepParserStepFactoryBean.class); - bd.setAttribute("isNamespaceStep", true); + bd.setBeanClass(StepFactoryBean.class); + bd.setAttribute("isNamespaceStep", false); String taskletRef = taskletElement.getAttribute(REF); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ChunkParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ChunkParser.java index 0c7dfbf5a..949fd557d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ChunkParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ChunkParser.java @@ -18,7 +18,6 @@ package org.springframework.batch.core.jsr.configuration.xml; import java.util.List; import org.springframework.batch.core.configuration.xml.ExceptionElementParser; -import org.springframework.batch.core.configuration.xml.StepParserStepFactoryBean; import org.springframework.batch.core.step.item.ChunkOrientedTasklet; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.ItemReader; @@ -67,7 +66,8 @@ public class ChunkParser { public void parse(Element element, AbstractBeanDefinition bd, ParserContext parserContext) { MutablePropertyValues propertyValues = bd.getPropertyValues(); - bd.setBeanClass(StepParserStepFactoryBean.class); + bd.setBeanClass(StepFactoryBean.class); + bd.setAttribute("isNamespaceStep", false); propertyValues.addPropertyValue("hasChunkElement", Boolean.TRUE); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobFactoryBean.java new file mode 100644 index 000000000..880478b55 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobFactoryBean.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013 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.listener.JobListener; + +import org.springframework.batch.core.JobExecutionListener; +import org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean; +import org.springframework.batch.core.job.flow.FlowJob; +import org.springframework.batch.core.jsr.JobListenerAdapter; +import org.springframework.beans.factory.FactoryBean; + +/** + * This {@link FactoryBean} is used by the JSR-352 namespace parser to create + * {@link FlowJob} objects. It stores all of the properties that are + * configurable on the <job/>. + * + * @author Michael Minella + * @since 3.0 + */ +public class JobFactoryBean extends JobParserJobFactoryBean { + + public JobFactoryBean(String name) { + super(name); + } + + /** + * Addresses wrapping {@link JobListener} as needed to be used with + * the framework. + * + * @param jobListeners a list of all job listeners + */ + public void setJobExecutionListeners(Object[] jobListeners) { + if(jobListeners != null) { + JobExecutionListener[] listeners = new JobExecutionListener[jobListeners.length]; + + for(int i = 0; i < jobListeners.length; i++) { + Object curListener = jobListeners[i]; + if(curListener instanceof JobExecutionListener) { + listeners[i] = (JobExecutionListener) curListener; + } else if(curListener instanceof JobListener){ + listeners[i] = new JobListenerAdapter((JobListener) curListener); + } + } + + super.setJobExecutionListeners(listeners); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobListenerFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobListenerFactoryBean.java new file mode 100644 index 000000000..6db8ad29c --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobListenerFactoryBean.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013 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 java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.batch.api.listener.JobListener; + +import org.springframework.batch.core.JobExecutionListener; +import org.springframework.batch.core.jsr.JsrJobListenerMetaData; +import org.springframework.batch.core.listener.JobListenerMetaData; +import org.springframework.batch.core.listener.ListenerMetaData; +import org.springframework.beans.factory.FactoryBean; + +/** + * This {@link FactoryBean} is used by the JSR-352 namespace parser to create + * {@link JobExecutionListener} objects. + * + * @author Michael Minella + * @since 3.0 + */ +public class JobListenerFactoryBean extends org.springframework.batch.core.listener.JobListenerFactoryBean { + + @Override + public Class getObjectType() { + return JobListener.class; + } + + @Override + protected ListenerMetaData[] getMetaDataValues() { + List values = new ArrayList(); + Collections.addAll(values, JobListenerMetaData.values()); + Collections.addAll(values, JsrJobListenerMetaData.values()); + + return values.toArray(new ListenerMetaData[0]); + } + + @Override + protected ListenerMetaData getMetaDataFromPropertyName(String propertyName) { + ListenerMetaData result = JobListenerMetaData.fromPropertyName(propertyName); + + if(result == null) { + result = JsrJobListenerMetaData.fromPropertyName(propertyName); + } + + return result; + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java index 7d0e87822..2d8829a37 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java @@ -16,8 +16,6 @@ package org.springframework.batch.core.jsr.configuration.xml; import org.springframework.batch.core.configuration.xml.CoreNamespaceUtils; -import org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean; -import org.springframework.batch.core.listener.JobListenerFactoryBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; @@ -38,8 +36,8 @@ public class JobParser extends AbstractSingleBeanDefinitionParser { private static final String ID_ATTRIBUTE = "id"; @Override - protected Class getBeanClass(Element element) { - return JobParserJobFactoryBean.class; + protected Class getBeanClass(Element element) { + return JobFactoryBean.class; } @Override diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ListnerParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ListnerParser.java index a3fed34fd..64c6bab3d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ListnerParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/ListnerParser.java @@ -66,7 +66,6 @@ public class ListnerParser { } private ManagedList parseListeners(Element element, ParserContext parserContext) { - List listenersElements = DomUtils.getChildElementsByTagName(element, LISTENERS_ELEMENT); ManagedList listeners = new ManagedList(); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/StepFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/StepFactoryBean.java new file mode 100644 index 000000000..7838115d3 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/StepFactoryBean.java @@ -0,0 +1,86 @@ +/* + * Copyright 2013 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.ItemProcessor; +import javax.batch.api.chunk.ItemReader; +import javax.batch.api.chunk.ItemWriter; + +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.xml.StepParserStepFactoryBean; +import org.springframework.batch.core.jsr.step.batchlet.BatchletAdapter; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.jsr.item.ItemProcessorAdapter; +import org.springframework.batch.jsr.item.ItemReaderAdapter; +import org.springframework.batch.jsr.item.ItemWriterAdapter; +import org.springframework.beans.factory.FactoryBean; + +/** + * 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 + * @since 3.0 + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class StepFactoryBean extends StepParserStepFactoryBean { + + public void setTasklet(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"); + } + } + + public void setItemReader(Object itemReader) { + if(itemReader instanceof org.springframework.batch.item.ItemReader) { + super.setItemReader((org.springframework.batch.item.ItemReader) itemReader); + } else if(itemReader instanceof ItemReader){ + super.setItemReader(new ItemReaderAdapter((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"); + } + } + + public void setItemProcessor(Object itemProcessor) { + if(itemProcessor instanceof org.springframework.batch.item.ItemProcessor) { + super.setItemProcessor((org.springframework.batch.item.ItemProcessor) itemProcessor); + } else if(itemProcessor instanceof ItemProcessor){ + super.setItemProcessor(new ItemProcessorAdapter((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"); + } + } + + public void setItemWriter(Object itemWriter) { + if(itemWriter instanceof org.springframework.batch.item.ItemWriter) { + super.setItemWriter((org.springframework.batch.item.ItemWriter) itemWriter); + } else if(itemWriter instanceof ItemWriter){ + super.setItemWriter(new ItemWriterAdapter((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"); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/StepParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/StepParser.java index 2214f316b..e26407363 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/StepParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/StepParser.java @@ -17,7 +17,6 @@ package org.springframework.batch.core.jsr.configuration.xml; import java.util.Collection; -import org.springframework.batch.core.configuration.xml.StepParserStepFactoryBean; import org.springframework.batch.core.job.flow.support.state.StepState; import org.springframework.batch.core.listener.StepListenerFactoryBean; import org.springframework.beans.factory.config.BeanDefinition; @@ -32,8 +31,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** - * Parser for the <step /> element defined by JSR-352. Current state parses it - * into existing Spring Batch artifacts. + * Parser for the <step /> element defined by JSR-352. * * @author Michael Minella * @since 3.0 @@ -46,15 +44,10 @@ public class StepParser extends AbstractSingleBeanDefinitionParser { private static final String START_LIMIT_ATTRIBUTE = "start-limit"; private static final String SPLIT_ID_ATTRIBUTE = "id"; - @Override - @SuppressWarnings("rawtypes") - protected Class getBeanClass(Element element) { - return StepParserStepFactoryBean.class; - } - protected Collection parse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(); AbstractBeanDefinition bd = defBuilder.getRawBeanDefinition(); + bd.setBeanClass(StepFactoryBean.class); BeanDefinitionBuilder stateBuilder = BeanDefinitionBuilder.genericBeanDefinition(StepState.class); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/launch/JsrJobOperator.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/launch/JsrJobOperator.java new file mode 100644 index 000000000..f6becc767 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/launch/JsrJobOperator.java @@ -0,0 +1,297 @@ +/* + * Copyright 2013 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.launch; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import javax.batch.operations.JobExecutionAlreadyCompleteException; +import javax.batch.operations.JobExecutionIsRunningException; +import javax.batch.operations.JobExecutionNotMostRecentException; +import javax.batch.operations.JobExecutionNotRunningException; +import javax.batch.operations.JobOperator; +import javax.batch.operations.JobRestartException; +import javax.batch.operations.JobSecurityException; +import javax.batch.operations.JobStartException; +import javax.batch.operations.NoSuchJobException; +import javax.batch.operations.NoSuchJobExecutionException; +import javax.batch.operations.NoSuchJobInstanceException; +import javax.batch.runtime.JobExecution; +import javax.batch.runtime.JobInstance; +import javax.batch.runtime.StepExecution; +import javax.sql.DataSource; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.explore.support.JobExplorerFactoryBean; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobOperator; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; + +/** + * The entrance for executing batch jobs as defined by JSR-352. This class provides + * a base {@link ApplicationContext} that is the equivalent to the following: + * + *
+ * 	@Configuration
+ * 	@EnableBatchProcessing
+ * 	public static class BaseConfiguration extends DefaultBatchConfigurer {
+ * 
+ * 		@Bean
+ * 		JobLauncher jobLauncher() { ... }
+ * 
+ * 		@Bean
+ * 		org.springframework.batch.core.launch.JobOperator batchJobOperator(JobExplorer jobExplorer,
+ * 																		   JobLauncher jobLauncher,
+ * 																		   JobRepository jobRepository,
+ * 																		   JobRegistry jobRegistry)  { ... }
+ * 
+ * 		@Bean
+ * 		JobExplorerFactoryBean jobExplorer(final DataSource dataSource)  { ... }
+ * 
+ * 		@Bean
+ * 		DataSource dataSource()  { ... }
+ * 	}
+ * 
+ * + * @author Michael Minella + * @since 3.0 + * @see EnableBatchProcessing + */ +public class JsrJobOperator implements JobOperator { + + private org.springframework.batch.core.launch.JobOperator batchJobOperator; + private JobExplorer jobExplorer; + private JobLauncher jobLauncher; + private GenericApplicationContext baseContext; + + public JsrJobOperator() { + baseContext = new AnnotationConfigApplicationContext(BaseConfiguration.class); + jobLauncher = baseContext.getBean(JobLauncher.class); + jobExplorer = baseContext.getBean(JobExplorer.class); + batchJobOperator = baseContext.getBean(org.springframework.batch.core.launch.JobOperator.class); + try { + ((SimpleJobLauncher) jobLauncher).afterPropertiesSet(); + ((SimpleJobOperator) batchJobOperator).afterPropertiesSet(); + } catch (Exception e) { + } + } + + @Override + public void abandon(long jobExecutionId) throws NoSuchJobExecutionException, + JobExecutionIsRunningException, JobSecurityException { + try { + batchJobOperator.abandon(jobExecutionId); + } catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) { + throw new NoSuchJobException(e); + } catch (JobExecutionAlreadyRunningException e) { + throw new JobExecutionIsRunningException(e); + } + } + + @Override + public JobExecution getJobExecution(long executionId) + throws NoSuchJobExecutionException, JobSecurityException { + org.springframework.batch.core.JobExecution jobExecution = jobExplorer.getJobExecution(executionId); + + if(jobExecution == null) { + throw new NoSuchJobException("No execution was found for executionId " + executionId); + } + + return new org.springframework.batch.core.jsr.JobExecution(jobExecution); + } + + @Override + public List getJobExecutions(JobInstance jobInstance) + throws NoSuchJobInstanceException, JobSecurityException { + org.springframework.batch.core.JobInstance instance = (org.springframework.batch.core.JobInstance) jobInstance; + List batchExecutions = jobExplorer.getJobExecutions(instance); + + if(batchExecutions == null) { + throw new NoSuchJobInstanceException("Unable to find JobInstance " + jobInstance.getInstanceId()); + } + + List results = new ArrayList(batchExecutions.size()); + for (org.springframework.batch.core.JobExecution jobExecution : batchExecutions) { + results.add(new org.springframework.batch.core.jsr.JobExecution(jobExecution)); + } + + return results; + } + + @Override + public JobInstance getJobInstance(long instanceId) + throws NoSuchJobExecutionException, JobSecurityException { + return jobExplorer.getJobInstance(instanceId); + } + + @Override + public int getJobInstanceCount(String arg0) throws NoSuchJobException, + JobSecurityException { + return 0; + } + + @Override + public List getJobInstances(String arg0, int arg1, int arg2) + throws NoSuchJobException, JobSecurityException { + return null; + } + + @Override + public Set getJobNames() throws JobSecurityException { + return new HashSet(jobExplorer.getJobNames()); + } + + @Override + public Properties getParameters(long executionId) + throws NoSuchJobExecutionException, JobSecurityException { + org.springframework.batch.core.JobExecution execution = jobExplorer.getJobExecution(executionId); + + if(execution == null) { + throw new NoSuchJobExecutionException("Unable to find the JobExecution for id " + executionId); + } + + return execution.getJobParameters().toProperties(); + } + + @Override + public List getRunningExecutions(String name) + throws NoSuchJobException, JobSecurityException { + Set findRunningJobExecutions = jobExplorer.findRunningJobExecutions(name); + List results = new ArrayList(findRunningJobExecutions.size()); + + for (org.springframework.batch.core.JobExecution jobExecution : findRunningJobExecutions) { + results.add(jobExecution.getId()); + } + + return results; + } + + @Override + public List getStepExecutions(long executionId) + throws NoSuchJobExecutionException, JobSecurityException { + org.springframework.batch.core.JobExecution execution = jobExplorer.getJobExecution(executionId); + + if(execution == null) { + throw new NoSuchJobException("JobExecution with the id " + executionId + " was not found"); + } + + return null; + // return execution.getStepExecutions(); + } + + @Override + public long restart(long arg0, Properties arg1) + throws JobExecutionAlreadyCompleteException, + NoSuchJobExecutionException, JobExecutionNotMostRecentException, + JobRestartException, JobSecurityException { + return 0; + } + + @Override + public long start(String jobName, Properties params) throws JobStartException, + JobSecurityException { + GenericXmlApplicationContext batchContext = new GenericXmlApplicationContext(); + batchContext.setValidating(false); + batchContext.load(new String[] {"/META-INF/batch.xml", "META-INF/batch-jobs/" + jobName + ".xml"}); + batchContext.setParent(baseContext); + GenericBeanDefinition bd = new GenericBeanDefinition(); + bd.setBeanClass(AutowiredAnnotationBeanPostProcessor.class); + batchContext.registerBeanDefinition("postProcessor", bd); + batchContext.refresh(); + Job job = batchContext.getBean(jobName, Job.class); + try { + return jobLauncher.run(job, new JobParametersBuilder(params).toJobParameters()).getId(); + } catch (Exception e) { + e.printStackTrace(); + throw new JobStartException(e); + } + } + + @Override + public void stop(long executionId) throws NoSuchJobExecutionException, + JobExecutionNotRunningException, JobSecurityException { + try { + batchJobOperator.stop(executionId); + } catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) { + throw new NoSuchJobException(e); + } catch (org.springframework.batch.core.launch.JobExecutionNotRunningException e) { + throw new JobExecutionNotRunningException(e); + } + } + + @Configuration + @EnableBatchProcessing + public static class BaseConfiguration extends DefaultBatchConfigurer { + + @Bean + JobLauncher jobLauncher() { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + jobLauncher.setJobRepository(super.getJobRepository()); + try { + jobLauncher.afterPropertiesSet(); + } catch (Exception e) { + e.printStackTrace(); + } + return jobLauncher; + } + + @Bean + org.springframework.batch.core.launch.JobOperator batchJobOperator(JobExplorer jobExplorer, JobLauncher jobLauncher, JobRepository jobRepository, JobRegistry jobRegistry) { + SimpleJobOperator operator = new SimpleJobOperator(); + + operator.setJobExplorer(jobExplorer); + operator.setJobLauncher(jobLauncher); + operator.setJobRepository(jobRepository); + operator.setJobRegistry(jobRegistry); + + return operator; + } + + @Bean + JobExplorerFactoryBean jobExplorer(final DataSource dataSource) { + return new JobExplorerFactoryBean() {{ + setDataSource(dataSource); + }}; + } + + @Bean + DataSource dataSource() { + return new EmbeddedDatabaseBuilder(). + addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql"). + addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql"). + build(); + } + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/batchlet/BatchletAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/batchlet/BatchletAdapter.java new file mode 100644 index 000000000..ec9992785 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/batchlet/BatchletAdapter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2013 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.step.batchlet; + +import javax.batch.api.Batchlet; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +//TODO: This needs to implement StoppableTasklet +public class BatchletAdapter implements Tasklet { + + private Batchlet batchlet; + + public BatchletAdapter(Batchlet batchlet) { + Assert.notNull(batchlet, "A Batchlet implementation is required"); + this.batchlet = batchlet; + } + + @Override + public RepeatStatus execute(StepContribution contribution, + ChunkContext chunkContext) throws Exception { + String exitStatus = batchlet.process(); + + if(StringUtils.hasText(exitStatus)) { + contribution.setExitStatus(new ExitStatus(exitStatus)); + } + + return RepeatStatus.FINISHED; + } + + //TODO: Once the stoppable tasklet is implemented...this will be good to go + // @Override + // public void stop() { + // batchlet.stop(); + // } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobLauncher.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobLauncher.java index 41dd76ac0..9500ccd42 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobLauncher.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobLauncher.java @@ -25,12 +25,18 @@ import org.springframework.batch.core.JobInstance; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersInvalidException; import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.jsr.JobContext; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.JobRestartException; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.task.SyncTaskExecutor; import org.springframework.core.task.TaskExecutor; import org.springframework.core.task.TaskRejectedException; @@ -55,13 +61,14 @@ import org.springframework.util.Assert; * @author Lucas Ward * @Author Dave Syer * @author Will Schipp + * @author Michael Minella * * @since 1.0 * * @see JobRepository * @see TaskExecutor */ -public class SimpleJobLauncher implements JobLauncher, InitializingBean { +public class SimpleJobLauncher implements JobLauncher, InitializingBean, ApplicationContextAware { protected static final Log logger = LogFactory.getLog(SimpleJobLauncher.class); @@ -69,6 +76,8 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean { private TaskExecutor taskExecutor; + private ApplicationContext context; + /** * Run the provided job with the given {@link JobParameters}. The * {@link JobParameters} will be used to determine if this is an execution @@ -106,15 +115,15 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean { for (StepExecution execution : lastExecution.getStepExecutions()) { if (execution.getStatus() == BatchStatus.UNKNOWN) { //throw - throw new JobRestartException("Step [" + execution.getStepName() + "] is of status UNKNOWN"); + throw new JobRestartException("Step [" + execution.getStepName() + "] is of status UNKNOWN"); }//end if - }//end for + }//end for } // Check the validity of the parameters before doing creating anything // in the repository... job.getJobParametersValidator().validate(jobParameters); - + /* * There is a very small probability that a non-restartable job can be * restarted, but only if another process or thread manages to launch @@ -123,6 +132,11 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean { */ jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters); + if(context != null && context instanceof ConfigurableApplicationContext) { + ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext)context).getBeanFactory(); + factory.registerSingleton(job.getName() + "_" + jobExecution.getId() + "_jobContext", new JobContext(jobExecution)); + } + try { taskExecutor.execute(new Runnable() { @@ -196,4 +210,9 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean { } } + @Override + public void setApplicationContext(ApplicationContext context) + throws BeansException { + this.context = context; + } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/AbstractListenerFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/AbstractListenerFactoryBean.java index 23604e4e4..762dc17da 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/AbstractListenerFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/AbstractListenerFactoryBean.java @@ -71,7 +71,6 @@ public abstract class AbstractListenerFactoryBean implements FactoryBean, Initia @Override public Object getObject() { - if (metaDataMap == null) { metaDataMap = new HashMap(); } @@ -92,12 +91,10 @@ public abstract class AbstractListenerFactoryBean implements FactoryBean, Initia Map> invokerMap = new HashMap>(); boolean synthetic = false; for (Entry entry : metaDataMap.entrySet()) { - final ListenerMetaData metaData = this.getMetaDataFromPropertyName(entry.getKey()); Set invokers = new HashSet(); MethodInvoker invoker; - invoker = getMethodInvokerForInterface(metaData.getListenerInterface(), metaData.getMethodName(), delegate, metaData.getParamTypes()); if (invoker != null) { @@ -110,10 +107,12 @@ public abstract class AbstractListenerFactoryBean implements FactoryBean, Initia synthetic = true; } - invoker = getMethodInvokerByAnnotation(metaData.getAnnotation(), delegate, metaData.getParamTypes()); - if (invoker != null) { - invokers.add(invoker); - synthetic = true; + if(metaData.getAnnotation() != null) { + invoker = getMethodInvokerByAnnotation(metaData.getAnnotation(), delegate, metaData.getParamTypes()); + if (invoker != null) { + invokers.add(invoker); + synthetic = true; + } } if (!invokers.isEmpty()) { diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java index e77ef8a60..087746034 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java @@ -15,7 +15,12 @@ */ package org.springframework.batch.core.listener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import org.springframework.batch.core.StepListener; +import org.springframework.batch.core.jsr.JsrStepListenerMetaData; /** * This {@link AbstractListenerFactoryBean} implementation is used to create a @@ -31,12 +36,22 @@ public class StepListenerFactoryBean extends AbstractListenerFactoryBean { @Override protected ListenerMetaData getMetaDataFromPropertyName(String propertyName) { - return StepListenerMetaData.fromPropertyName(propertyName); + ListenerMetaData metaData = StepListenerMetaData.fromPropertyName(propertyName); + + if(metaData == null) { + metaData = JsrStepListenerMetaData.fromPropertyName(propertyName); + } + + return metaData; } @Override protected ListenerMetaData[] getMetaDataValues() { - return StepListenerMetaData.values(); + List values = new ArrayList(); + Collections.addAll(values, StepListenerMetaData.values()); + Collections.addAll(values, JsrStepListenerMetaData.values()); + + return values.toArray(new ListenerMetaData[0]); } @Override diff --git a/spring-batch-core-tests/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExcutionWaiterFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExcutionWaiterFactory.java similarity index 100% rename from spring-batch-core-tests/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExcutionWaiterFactory.java rename to spring-batch-core/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExcutionWaiterFactory.java diff --git a/spring-batch-core-tests/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExecutionWaiter.java b/spring-batch-core/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExecutionWaiter.java similarity index 100% rename from spring-batch-core-tests/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExecutionWaiter.java rename to spring-batch-core/src/main/java/org/springframework/batch/jsr/tck/spi/SpringJobExecutionWaiter.java diff --git a/spring-batch-core/src/main/resources/META-INF/services/javax.batch.operations.JobOperator b/spring-batch-core/src/main/resources/META-INF/services/javax.batch.operations.JobOperator new file mode 100644 index 000000000..7bb1f526d --- /dev/null +++ b/spring-batch-core/src/main/resources/META-INF/services/javax.batch.operations.JobOperator @@ -0,0 +1 @@ +org.springframework.batch.core.jsr.launch.JsrJobOperator \ No newline at end of file diff --git a/spring-batch-core/src/main/resources/META-INF/spring.schemas b/spring-batch-core/src/main/resources/META-INF/spring.schemas index 375d61f6b..c74486234 100644 --- a/spring-batch-core/src/main/resources/META-INF/spring.schemas +++ b/spring-batch-core/src/main/resources/META-INF/spring.schemas @@ -2,5 +2,5 @@ http\://www.springframework.org/schema/batch/spring-batch.xsd=/org/springframewo http\://www.springframework.org/schema/batch/spring-batch-2.2.xsd=/org/springframework/batch/core/configuration/xml/spring-batch-2.2.xsd http\://www.springframework.org/schema/batch/spring-batch-2.1.xsd=/org/springframework/batch/core/configuration/xml/spring-batch-2.1.xsd http\://www.springframework.org/schema/batch/spring-batch-2.0.xsd=/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd -http\://xmlns.jcp.org/xml/ns/javaee=/org/springframework/batch/core/jsr/configuration/xml/jobXML_1_0.xsd -http\://xmlns.jcp.org/xml/ns/javaee=/org/springframework/batch/core/jsr/configuration/xml/batchXML_1_0.xsd +http\://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd=/org/springframework/batch/core/jsr/configuration/xml/jobXML_1_0.xsd +http\://xmlns.jcp.org/xml/ns/javaee/batchXML_1_0.xsd=/org/springframework/batch/core/jsr/configuration/xml/batchXML_1_0.xsd diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/BatchStatusTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/BatchStatusTests.java index c4ac077fb..168befa23 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/BatchStatusTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/BatchStatusTests.java @@ -30,7 +30,7 @@ import org.junit.Test; /** * @author Dave Syer - * + * */ public class BatchStatusTests { @@ -118,4 +118,15 @@ public class BatchStatusTests { BatchStatus status = (BatchStatus) in.readObject(); assertEquals(BatchStatus.COMPLETED, status); } + + @Test + public void testJsrConversion() { + assertEquals(javax.batch.runtime.BatchStatus.ABANDONED, BatchStatus.ABANDONED.getBatchStatus()); + assertEquals(javax.batch.runtime.BatchStatus.COMPLETED, BatchStatus.COMPLETED.getBatchStatus()); + assertEquals(javax.batch.runtime.BatchStatus.STARTED, BatchStatus.STARTED.getBatchStatus()); + assertEquals(javax.batch.runtime.BatchStatus.STARTING, BatchStatus.STARTING.getBatchStatus()); + assertEquals(javax.batch.runtime.BatchStatus.STOPPED, BatchStatus.STOPPED.getBatchStatus()); + assertEquals(javax.batch.runtime.BatchStatus.STOPPING, BatchStatus.STOPPING.getBatchStatus()); + assertEquals(javax.batch.runtime.BatchStatus.FAILED, BatchStatus.FAILED.getBatchStatus()); + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/JobInstanceTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/JobInstanceTests.java index c3a1ac594..4fbc78c02 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/JobInstanceTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/JobInstanceTests.java @@ -15,15 +15,17 @@ */ package org.springframework.batch.core; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import org.junit.Test; import org.springframework.batch.support.SerializationUtils; /** * @author dsyer * */ -public class JobInstanceTests extends TestCase { +public class JobInstanceTests { private JobInstance instance = new JobInstance(new Long(11), "job"); @@ -31,15 +33,18 @@ public class JobInstanceTests extends TestCase { * Test method for * {@link org.springframework.batch.core.JobInstance#getJobName()}. */ + @Test public void testGetName() { instance = new JobInstance(new Long(1), "foo"); assertEquals("foo", instance.getJobName()); } + @Test public void testGetJob() { assertEquals("job", instance.getJobName()); } + @Test public void testCreateWithNulls() { try { new JobInstance(null, null); @@ -52,6 +57,7 @@ public class JobInstanceTests extends TestCase { assertEquals("testJob", instance.getJobName()); } + @Test public void testSerialization() { instance = new JobInstance(new Long(1), "jobName"); @@ -59,4 +65,9 @@ public class JobInstanceTests extends TestCase { assertEquals(instance, SerializationUtils.deserialize(serialized)); } + + @Test + public void testGetInstanceId() { + assertEquals(11, instance.getInstanceId()); + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java index aca692377..bc563f4df 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertFalse; import java.util.Date; import java.util.Iterator; import java.util.Map; +import java.util.Properties; import org.junit.Test; @@ -20,6 +21,30 @@ public class JobParametersBuilderTests { Date date = new Date(System.currentTimeMillis()); + @Test + public void testFromProperties() { + Properties props = new Properties(); + props.put("SCHEDULE_DATE", date.toString()); + props.put("LONG", "1"); + props.put("STRING", "string value"); + + JobParametersBuilder builder = new JobParametersBuilder(props); + JobParameters parameters = builder.toJobParameters(); + assertEquals(date.toString(), parameters.getString("SCHEDULE_DATE")); + assertEquals("1", parameters.getString("LONG").toString()); + assertEquals("string value", parameters.getString("STRING")); + assertFalse(parameters.getParameters().get("SCHEDULE_DATE").isIdentifying()); + assertFalse(parameters.getParameters().get("LONG").isIdentifying()); + assertFalse(parameters.getParameters().get("STRING").isIdentifying()); + } + + @Test + public void testFromNullProperties() { + JobParametersBuilder builder = new JobParametersBuilder((Properties) null); + JobParameters parameters = builder.toJobParameters(); + assertEquals(0, parameters.getParameters().size()); + } + @Test public void testNonIdentifyingParameters() { parametersBuilder.addDate("SCHEDULE_DATE", date, false); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersTests.java index e7a8c62d7..119584b1a 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersTests.java @@ -10,6 +10,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.Properties; import org.junit.Before; import org.junit.Test; @@ -212,4 +213,18 @@ public class JobParametersTests { public void testDateReturnsNullWhenKeyDoesntExit(){ assertNull(new JobParameters().getDate("keythatdoesntexist")); } + + @Test + public void testToProperties() { + Properties results = parameters.toProperties(); + + assertEquals(results.get("string.key1"), "value1"); + assertEquals(results.get("string.key2"), "value2"); + assertEquals(results.get("long.key1"), "1"); + assertEquals(results.get("long.key2"), "2"); + assertEquals(results.get("double.key1"), "1.1"); + assertEquals(results.get("double.key2"), "2.2"); + assertEquals(results.get("date.key1"), String.valueOf(date1.getTime())); + assertEquals(results.get("date.key2"), String.valueOf(date2.getTime())); + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java index 5c1c1d829..5e8adf708 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java @@ -25,13 +25,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.aop.framework.Advised; import org.springframework.batch.core.Step; import org.springframework.batch.core.StepExecutionListener; -import org.springframework.batch.core.StepListener; import org.springframework.batch.core.job.AbstractJob; import org.springframework.batch.core.listener.CompositeStepExecutionListener; import org.springframework.batch.core.listener.StepExecutionListenerSupport; @@ -446,7 +446,7 @@ public class StepParserTests { Map, Boolean> retryableFound = getExceptionMap(fb, "retryableExceptionClasses"); ItemStream[] streamsFound = (ItemStream[]) ReflectionTestUtils.getField(fb, "streams"); RetryListener[] retryListenersFound = (RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners"); - StepListener[] stepListenersFound = (StepListener[]) ReflectionTestUtils.getField(fb, "listeners"); + Set stepListenersFound = (Set) ReflectionTestUtils.getField(fb, "stepExecutionListeners"); Collection> noRollbackFound = getExceptionList(fb, "noRollbackExceptionClasses"); assertSameMaps(skippable, skippableFound); @@ -480,7 +480,7 @@ public class StepParserTests { Map, Boolean> retryableFound = getExceptionMap(fb, "retryableExceptionClasses"); ItemStream[] streamsFound = (ItemStream[]) ReflectionTestUtils.getField(fb, "streams"); RetryListener[] retryListenersFound = (RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners"); - StepListener[] stepListenersFound = (StepListener[]) ReflectionTestUtils.getField(fb, "listeners"); + Set stepListenersFound = (Set) ReflectionTestUtils.getField(fb, "stepExecutionListeners"); Collection> noRollbackFound = getExceptionList(fb, "noRollbackExceptionClasses"); assertSameMaps(skippable, skippableFound); @@ -491,6 +491,7 @@ public class StepParserTests { assertSameCollections(noRollback, noRollbackFound); } + @SuppressWarnings("unchecked") @Test public void testStepWithListsOverrideWithEmpty() throws Exception { ApplicationContext ctx = stepParserParentAttributeTestsCtx; @@ -502,7 +503,7 @@ public class StepParserTests { assertEquals(1, getExceptionMap(fb, "retryableExceptionClasses").size()); assertEquals(0, ((ItemStream[]) ReflectionTestUtils.getField(fb, "streams")).length); assertEquals(0, ((RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners")).length); - assertEquals(0, ((StepListener[]) ReflectionTestUtils.getField(fb, "listeners")).length); + assertEquals(0, ((Set) ReflectionTestUtils.getField(fb, "stepExecutionListeners")).size()); assertEquals(0, getExceptionList(fb, "noRollbackExceptionClasses").size()); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests.java index 580fa20d0..9b09bf27e 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests.java @@ -19,13 +19,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.util.Set; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.StepListener; +import org.springframework.batch.core.StepExecutionListener; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.item.ItemStream; import org.springframework.beans.factory.annotation.Autowired; @@ -42,36 +44,37 @@ import org.springframework.test.util.ReflectionTestUtils; @ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class StepWithBasicProcessTaskJobParserTests { - + @Autowired private Job job; @Autowired private JobRepository jobRepository; - + @Autowired private TestReader reader; - + @Autowired @Qualifier("listener") private TestListener listener; - + @Autowired private TestProcessor processor; - + @Autowired private TestWriter writer; - + @Autowired private StepParserStepFactoryBean factory; - + + @SuppressWarnings("unchecked") @Test public void testStepWithTask() throws Exception { assertNotNull(job); Object ci = ReflectionTestUtils.getField(factory, "commitInterval"); assertEquals("wrong chunk-size:", 10, ci); - Object listeners = ReflectionTestUtils.getField(factory, "listeners"); - assertEquals("wrong number of listeners:", 2, ((StepListener[])listeners).length); + Object listeners = ReflectionTestUtils.getField(factory, "stepExecutionListeners"); + assertEquals("wrong number of listeners:", 2, ((Set)listeners).size()); Object streams = ReflectionTestUtils.getField(factory, "streams"); assertEquals("wrong number of streams:", 1, ((ItemStream[])streams).length); JobExecution jobExecution = jobRepository.createJobExecution(job.getName(), new JobParameters()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests.java index 395404f31..d1e81e89a 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests.java @@ -19,13 +19,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.util.Set; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.StepListener; +import org.springframework.batch.core.StepExecutionListener; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.item.ItemStream; import org.springframework.beans.factory.annotation.Autowired; @@ -40,7 +42,7 @@ import org.springframework.transaction.annotation.Propagation; /** * @author Thomas Risberg - * + * */ @ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) @@ -71,6 +73,7 @@ public class StepWithFaultTolerantProcessTaskJobParserTests { @Autowired private StepParserStepFactoryBean factory; + @SuppressWarnings("unchecked") @Test public void testStepWithTask() throws Exception { assertNotNull(job); @@ -91,8 +94,8 @@ public class StepWithFaultTolerantProcessTaskJobParserTests { assertEquals("wrong reader-transactional-queue:", true, txq); Object te = ReflectionTestUtils.getField(factory, "taskExecutor"); assertEquals("wrong task-executor:", ConcurrentTaskExecutor.class, te.getClass()); - Object listeners = ReflectionTestUtils.getField(factory, "listeners"); - assertEquals("wrong number of listeners:", 2, ((StepListener[]) listeners).length); + Object listeners = ReflectionTestUtils.getField(factory, "stepExecutionListeners"); + assertEquals("wrong number of listeners:", 2, ((Set) listeners).size()); Object retryListeners = ReflectionTestUtils.getField(factory, "retryListeners"); assertEquals("wrong number of retry-listeners:", 2, ((RetryListener[]) retryListeners).length); Object streams = ReflectionTestUtils.getField(factory, "streams"); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ChunkListenerAdapterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ChunkListenerAdapterTests.java new file mode 100644 index 000000000..dabfbd213 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ChunkListenerAdapterTests.java @@ -0,0 +1,82 @@ +package org.springframework.batch.core.jsr; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.batch.api.chunk.listener.ChunkListener; +import javax.batch.operations.BatchRuntimeException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.batch.core.scope.context.ChunkContext; + +public class ChunkListenerAdapterTests { + + private ChunkListenerAdapter adapter; + @Mock + private ChunkListener delegate; + @Mock + private ChunkContext context; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + adapter = new ChunkListenerAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullDelegate() { + adapter = new ChunkListenerAdapter(null); + } + + @Test + public void testBeforeChunk() throws Exception { + adapter.beforeChunk(null); + + verify(delegate).beforeChunk(); + } + + @Test(expected=BatchRuntimeException.class) + public void testBeforeChunkException() throws Exception { + doThrow(new Exception("This is expected")).when(delegate).beforeChunk(); + adapter.beforeChunk(null); + } + + @Test + public void testAfterChunk() throws Exception { + adapter.afterChunk(null); + + verify(delegate).afterChunk(); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterChunkException() throws Exception { + doThrow(new Exception("This is expected")).when(delegate).afterChunk(); + adapter.afterChunk(null); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterChunkErrorNullContext() throws Exception { + adapter.afterChunkError(null); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterChunkErrorException() throws Exception { + doThrow(new Exception("This is expected")).when(delegate).afterChunk(); + adapter.afterChunk(null); + } + + @Test + public void testAfterChunkError() throws Exception { + Exception exception = new Exception("This was expected"); + + when(context.getAttribute(org.springframework.batch.core.ChunkListener.ROLLBACK_EXCEPTION_KEY)).thenReturn(exception); + + adapter.afterChunkError(context); + + verify(delegate).onError(exception); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemProcessListenerAdapterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemProcessListenerAdapterTests.java new file mode 100644 index 000000000..947d4810b --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemProcessListenerAdapterTests.java @@ -0,0 +1,91 @@ +package org.springframework.batch.core.jsr; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +import javax.batch.api.chunk.listener.ItemProcessListener; +import javax.batch.operations.BatchRuntimeException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class ItemProcessListenerAdapterTests { + + private ItemProcessListenerAdapter adapter; + @Mock + private ItemProcessListener delegate; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + adapter = new ItemProcessListenerAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullCreation() { + adapter = new ItemProcessListenerAdapter(null); + } + + @Test + public void testBeforeProcess() throws Exception { + String item = "This is my item"; + + adapter.beforeProcess(item); + + verify(delegate).beforeProcess(item); + } + + @Test(expected=BatchRuntimeException.class) + public void testBeforeProcessException() throws Exception { + Exception exception = new Exception("This should occur"); + String item = "This is the bad item"; + + doThrow(exception).when(delegate).beforeProcess(item); + + adapter.beforeProcess(item); + } + + @Test + public void testAfterProcess() throws Exception { + String item = "This is the input"; + String result = "This is the output"; + + adapter.afterProcess(item, result); + + verify(delegate).afterProcess(item, result); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterProcessException() throws Exception { + String item = "This is the input"; + String result = "This is the output"; + Exception exception = new Exception("This is expected"); + + doThrow(exception).when(delegate).afterProcess(item, result); + + adapter.afterProcess(item, result); + } + + @Test + public void testOnProcessError() throws Exception { + String item = "This is the input"; + Exception cause = new Exception("This was the cause"); + + adapter.onProcessError(item, cause); + + verify(delegate).onProcessError(item, cause); + } + + @Test(expected=BatchRuntimeException.class) + public void testOnProcessErrorException() throws Exception { + String item = "This is the input"; + Exception cause = new Exception("This was the cause"); + Exception exception = new Exception("This is expected"); + + doThrow(exception).when(delegate).onProcessError(item, cause); + + adapter.onProcessError(item, cause); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemReadListenerAdapterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemReadListenerAdapterTests.java new file mode 100644 index 000000000..9cc12cdd8 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemReadListenerAdapterTests.java @@ -0,0 +1,82 @@ +package org.springframework.batch.core.jsr; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +import javax.batch.api.chunk.listener.ItemReadListener; +import javax.batch.operations.BatchRuntimeException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class ItemReadListenerAdapterTests { + + private ItemReadListenerAdapter adapter; + @Mock + private ItemReadListener delegate; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + adapter = new ItemReadListenerAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullDelegate() { + adapter = new ItemReadListenerAdapter(null); + } + + @Test + public void testBeforeRead() throws Exception { + adapter.beforeRead(); + + verify(delegate).beforeRead(); + } + + @Test(expected=BatchRuntimeException.class) + public void testBeforeReadException() throws Exception { + doThrow(new Exception("Should occur")).when(delegate).beforeRead(); + + adapter.beforeRead(); + } + + @Test + public void testAfterRead() throws Exception { + String item = "item"; + + adapter.afterRead(item); + + verify(delegate).afterRead(item); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterReadException() throws Exception { + String item = "item"; + Exception expected = new Exception("expected"); + + doThrow(expected).when(delegate).afterRead(item); + + adapter.afterRead(item); + } + + @Test + public void testOnReadError() throws Exception { + Exception cause = new Exception ("cause"); + + adapter.onReadError(cause); + + verify(delegate).onReadError(cause); + } + + @Test(expected=BatchRuntimeException.class) + public void testOnReadErrorException() throws Exception { + Exception cause = new Exception ("cause"); + Exception result = new Exception("result"); + + doThrow(result).when(delegate).onReadError(cause); + + adapter.onReadError(cause); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemWriteListenerAdapterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemWriteListenerAdapterTests.java new file mode 100644 index 000000000..fce7b3590 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/ItemWriteListenerAdapterTests.java @@ -0,0 +1,81 @@ +package org.springframework.batch.core.jsr; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; +import java.util.List; + +import javax.batch.api.chunk.listener.ItemWriteListener; +import javax.batch.operations.BatchRuntimeException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class ItemWriteListenerAdapterTests { + + private ItemWriteListenerAdapter adapter; + @Mock + private ItemWriteListener delegate; + private List items = new ArrayList(); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + adapter = new ItemWriteListenerAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new ItemWriteListenerAdapter(null); + } + + @Test + public void testBeforeWrite() throws Exception { + adapter.beforeWrite(items); + + verify(delegate).beforeWrite(items); + } + + @Test(expected=BatchRuntimeException.class) + public void testBeforeTestWriteException() throws Exception { + doThrow(new Exception("expected")).when(delegate).beforeWrite(items); + + adapter.beforeWrite(items); + } + + @Test + public void testAfterWrite() throws Exception { + adapter.afterWrite(items); + + verify(delegate).afterWrite(items); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterTestWriteException() throws Exception { + doThrow(new Exception("expected")).when(delegate).afterWrite(items); + + adapter.afterWrite(items); + } + + @Test + public void testOnWriteError() throws Exception { + Exception cause = new Exception("cause"); + + adapter.onWriteError(cause, items); + + verify(delegate).onWriteError(items, cause); + } + + @Test(expected=BatchRuntimeException.class) + public void testOnWriteErrorException() throws Exception { + Exception cause = new Exception("cause"); + + doThrow(new Exception("expected")).when(delegate).onWriteError(items, cause); + + adapter.onWriteError(cause, items); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobContextTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobContextTests.java new file mode 100644 index 000000000..fb6f137c9 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobContextTests.java @@ -0,0 +1,97 @@ +package org.springframework.batch.core.jsr; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; + +public class JobContextTests { + + private JobContext context; + @Mock + private JobExecution execution; + @Mock + private JobInstance instance; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + context = new JobContext(execution); + when(execution.getJobInstance()).thenReturn(instance); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + context = new JobContext(null); + } + + @Test + public void testGetJobName() { + when(instance.getJobName()).thenReturn("jobName"); + + assertEquals("jobName", context.getJobName()); + } + + @Test + public void testTransientUserData() { + context.setTransientUserData("This is my data"); + assertEquals("This is my data", context.getTransientUserData()); + } + + @Test + public void testGetInstanceId() { + when(instance.getId()).thenReturn(5L); + + assertEquals(5L, context.getInstanceId()); + } + + @Test + public void testGetExecutionId() { + when(execution.getId()).thenReturn(5L); + + assertEquals(5L, context.getExecutionId()); + } + + @Test + public void testGetProperties() { + JobParameters params = new JobParametersBuilder() + .addString("key1", "value1") + .toJobParameters(); + + when(execution.getJobParameters()).thenReturn(params); + + Properties props = context.getProperties(); + + assertEquals("value1", props.get("key1")); + } + + @Test + public void testGetBatchStatus() { + when(execution.getStatus()).thenReturn(BatchStatus.COMPLETED); + + assertEquals(javax.batch.runtime.BatchStatus.COMPLETED, context.getBatchStatus()); + } + + @Test + public void testExitStatus() { + when(execution.getExitStatus()).thenReturn(new ExitStatus("exit")); + + assertEquals("exit", context.getExitStatus()); + + context.setExitStatus("my exit status"); + + verify(execution).setExitStatus(new ExitStatus("my exit status")); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobExecutionTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobExecutionTests.java new file mode 100644 index 000000000..0bb970121 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobExecutionTests.java @@ -0,0 +1,60 @@ +package org.springframework.batch.core.jsr; + +import static org.junit.Assert.assertEquals; + +import java.util.Date; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; + +public class JobExecutionTests { + + private JobExecution adapter; + + @Before + public void setUp() throws Exception { + JobInstance instance = new JobInstance(2L, "job name"); + + JobParameters params = new JobParametersBuilder().addString("key1", "value1").toJobParameters(); + + org.springframework.batch.core.JobExecution execution = new org.springframework.batch.core.JobExecution(instance, params); + + execution.setId(5L); + execution.setCreateTime(new Date(0)); + execution.setEndTime(new Date(999999999l)); + execution.setExitStatus(new ExitStatus("exit status")); + execution.setLastUpdated(new Date(12345)); + execution.setStartTime(new Date(98765)); + execution.setStatus(BatchStatus.FAILED); + execution.setVersion(21); + + adapter = new JobExecution(execution); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new JobExecution(null); + } + + @Test + public void testGetBasicValues() { + assertEquals(javax.batch.runtime.BatchStatus.FAILED, adapter.getBatchStatus()); + assertEquals(new Date(0), adapter.getCreateTime()); + assertEquals(new Date(999999999l), adapter.getEndTime()); + assertEquals(5L, adapter.getExecutionId()); + assertEquals("exit status", adapter.getExitStatus()); + assertEquals("job name", adapter.getJobName()); + assertEquals(new Date(12345), adapter.getLastUpdatedTime()); + assertEquals(new Date(98765), adapter.getStartTime()); + + Properties props = adapter.getJobParameters(); + + assertEquals("value1", props.get("key1")); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobListenerAdapterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobListenerAdapterTests.java new file mode 100644 index 000000000..b9a78da2f --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/JobListenerAdapterTests.java @@ -0,0 +1,58 @@ +package org.springframework.batch.core.jsr; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +import javax.batch.api.listener.JobListener; +import javax.batch.operations.BatchRuntimeException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class JobListenerAdapterTests { + + private JobListenerAdapter adapter; + @Mock + private JobListener delegate; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + adapter = new JobListenerAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new JobListenerAdapter(null); + } + + @Test + public void testBeforeJob() throws Exception { + adapter.beforeJob(null); + + verify(delegate).beforeJob(); + } + + @Test(expected=BatchRuntimeException.class) + public void testBeforeJobException() throws Exception { + doThrow(new Exception("expected")).when(delegate).beforeJob(); + + adapter.beforeJob(null); + } + + @Test + public void testAfterJob() throws Exception { + adapter.afterJob(null); + + verify(delegate).afterJob(); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterJobException() throws Exception { + doThrow(new Exception("expected")).when(delegate).afterJob(); + + adapter.afterJob(null); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/StepListenerAdapterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/StepListenerAdapterTests.java new file mode 100644 index 000000000..12587f958 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/StepListenerAdapterTests.java @@ -0,0 +1,68 @@ +package org.springframework.batch.core.jsr; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.batch.api.listener.StepListener; +import javax.batch.operations.BatchRuntimeException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepExecution; + +public class StepListenerAdapterTests { + + private StepListenerAdapter adapter; + @Mock + private StepListener delegate; + @Mock + private StepExecution execution; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + adapter = new StepListenerAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new StepListenerAdapter(null); + } + + @Test + public void testBeforeStep() throws Exception { + adapter.beforeStep(null); + + verify(delegate).beforeStep(); + } + + @Test(expected=BatchRuntimeException.class) + public void testBeforeStepException() throws Exception { + doThrow(new Exception("expected")).when(delegate).beforeStep(); + + adapter.beforeStep(null); + } + + @Test + public void testAfterStep() throws Exception { + ExitStatus exitStatus = new ExitStatus("complete"); + when(execution.getExitStatus()).thenReturn(exitStatus); + + assertEquals(exitStatus, adapter.afterStep(execution)); + + verify(delegate).afterStep(); + } + + @Test(expected=BatchRuntimeException.class) + public void testAfterStepException() throws Exception { + doThrow(new Exception("expected")).when(delegate).afterStep(); + + adapter.afterStep(null); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/BatchParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/BatchParserTests.java index ad0a9b46b..8afc4694a 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/BatchParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/BatchParserTests.java @@ -1,36 +1,76 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import javax.sql.DataSource; + +import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; -import org.junit.runner.RunWith; +import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.xml.DummyItemProcessor; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.support.PassThroughItemProcessor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -@ContextConfiguration(value="batch.xml") -@RunWith(SpringJUnit4ClassRunner.class) public class BatchParserTests { - @Autowired - @Qualifier("itemProcessor") - @SuppressWarnings("rawtypes") - private ItemProcessor itemProcessor; + private ApplicationContext baseContext; - @Test - public void testRoseyScenario() { - assertNotNull(itemProcessor); - assertTrue(itemProcessor instanceof PassThroughItemProcessor); + @Before + public void setUp() { + baseContext = new AnnotationConfigApplicationContext(BaseConfiguration.class); } @Test + @Ignore + public void testRoseyScenario() { + GenericXmlApplicationContext batchContext = new GenericXmlApplicationContext(); + batchContext.setValidating(false); + batchContext.load(new String[] {"classpath:/org/springframework/batch/core/jsr/configuration/xml/batch.xml"}); + System.out.println("baseContext = " + baseContext); + batchContext.setParent(baseContext); + GenericBeanDefinition bd = new GenericBeanDefinition(); + bd.setBeanClass(AutowiredAnnotationBeanPostProcessor.class); + batchContext.registerBeanDefinition("postProcessor", bd); + batchContext.refresh(); + + Object itemProcessor = batchContext.getBean(ItemProcessor.class); + + assertNotNull(itemProcessor); + assertTrue(itemProcessor instanceof PassThroughItemProcessor); + + batchContext.close(); + } + + @Test + @Ignore @SuppressWarnings({"resource", "rawtypes"}) public void testOverrideBeansFirst() { AbstractApplicationContext context = new ClassPathXmlApplicationContext("/org/springframework/batch/core/jsr/configuration/xml/override_batch.xml", @@ -43,6 +83,7 @@ public class BatchParserTests { } @Test + @Ignore @SuppressWarnings({"resource", "rawtypes"}) public void testOverrideBeansLast() { AbstractApplicationContext context = new ClassPathXmlApplicationContext("/org/springframework/batch/core/jsr/configuration/xml/batch.xml", @@ -53,4 +94,17 @@ public class BatchParserTests { assertNotNull(processor); assertTrue(processor instanceof DummyItemProcessor); } + + @Configuration + @EnableBatchProcessing + public static class BaseConfiguration extends DefaultBatchConfigurer { + + @Bean + DataSource dataSource() { + return new EmbeddedDatabaseBuilder(). + addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql"). + addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql"). + build(); + } + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ChunkListenerParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ChunkListenerParsingTests.java new file mode 100644 index 000000000..78c3a1e94 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ChunkListenerParsingTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; + +import java.util.List; + +import javax.batch.api.chunk.AbstractItemWriter; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ChunkListener; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class ChunkListenerParsingTests { + + @Autowired + public Job job; + + @Autowired + public JobLauncher jobLauncher; + + @Autowired + public SpringChunkListener springChunkListener; + + @Autowired + public JsrChunkListener jsrChunkListener; + + @Test + public void test() throws Exception { + JobExecution execution = jobLauncher.run(job, new JobParameters()); + assertEquals(BatchStatus.FAILED, execution.getStatus()); + assertEquals(3, execution.getStepExecutions().size()); + assertEquals(4, springChunkListener.beforeChunkCount); + assertEquals(3, springChunkListener.afterChunkCount); + assertEquals(4, jsrChunkListener.beforeChunkCount); + assertEquals(3, jsrChunkListener.afterChunkCount); + assertEquals(1, springChunkListener.afterChunkErrorCount); + assertEquals(1, jsrChunkListener.afterChunkErrorCount); + } + + public static class SpringChunkListener implements ChunkListener { + + protected int beforeChunkCount = 0; + protected int afterChunkCount = 0; + protected int afterChunkErrorCount = 0; + + @Override + public void beforeChunk(ChunkContext context) { + beforeChunkCount++; + } + + @Override + public void afterChunk(ChunkContext context) { + afterChunkCount++; + } + + @Override + public void afterChunkError(ChunkContext context) { + afterChunkErrorCount++; + } + } + + public static class JsrChunkListener implements javax.batch.api.chunk.listener.ChunkListener { + + protected int beforeChunkCount = 0; + protected int afterChunkCount = 0; + protected int afterChunkErrorCount = 0; + + @Override + public void beforeChunk() throws Exception { + beforeChunkCount++; + } + + @Override + public void onError(Exception ex) throws Exception { + afterChunkErrorCount++; + } + + @Override + public void afterChunk() throws Exception { + afterChunkCount++; + } + } + + public static class ErrorThrowingItemWriter extends AbstractItemWriter { + + @Override + public void writeItems(List items) throws Exception { + throw new Exception("This should cause the rollback"); + } + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/CountingItemProcessor.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/CountingItemProcessor.java new file mode 100644 index 000000000..3f43ac299 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/CountingItemProcessor.java @@ -0,0 +1,14 @@ +package org.springframework.batch.core.jsr.configuration.xml; + +import javax.batch.api.chunk.ItemProcessor; + + +public class CountingItemProcessor implements ItemProcessor { + protected int count = 0; + + @Override + public Object processItem(Object item) throws Exception { + count++; + return item; + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java index 0b087d033..e8d743f94 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java @@ -1,7 +1,23 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; @@ -16,7 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ContextConfiguration({"DecisionParsingTests-context.xml", "jsr-base-context.xml"}) +@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class DecisionParsingTests { @@ -27,6 +43,7 @@ public class DecisionParsingTests { public JobLauncher jobLauncher; @Test + @Ignore public void test() throws Exception { JobExecution execution = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.COMPLETED, execution.getStatus()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests.java index 16c94b33f..e7905668e 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests.java @@ -1,3 +1,18 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; @@ -6,6 +21,7 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; @@ -19,7 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ContextConfiguration({"ExceptionHandlingParsingTests-context.xml", "jsr-base-context.xml"}) +@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class ExceptionHandlingParsingTests { @@ -30,6 +46,7 @@ public class ExceptionHandlingParsingTests { public JobLauncher jobLauncher; @Test + @Ignore public void testSkippable() throws Exception { JobExecution execution1 = jobLauncher.run(job, new JobParametersBuilder().addLong("run", 1l).toJobParameters()); assertEquals(BatchStatus.FAILED, execution1.getStatus()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ItemListenerParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ItemListenerParsingTests.java new file mode 100644 index 000000000..094a2f6ed --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ItemListenerParsingTests.java @@ -0,0 +1,188 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ItemProcessListener; +import org.springframework.batch.core.ItemReadListener; +import org.springframework.batch.core.ItemWriteListener; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class ItemListenerParsingTests { + + @Autowired + public Job job; + + @Autowired + public JobLauncher jobLauncher; + + @Autowired + public SpringItemListener springListener; + + @Autowired + public JsrItemListener jsrListener; + + @Test + public void test() throws Exception { + JobExecution execution = jobLauncher.run(job, new JobParameters()); + assertEquals(BatchStatus.COMPLETED, execution.getStatus()); + assertEquals(3, execution.getStepExecutions().size()); + assertEquals(6, springListener.beforeReadCount); + assertEquals(4, springListener.afterReadCount); + assertEquals(4, springListener.beforeProcessCount); + assertEquals(4, springListener.afterProcessCount); + assertEquals(2, springListener.beforeWriteCount); + assertEquals(2, springListener.afterWriteCount); + assertEquals(6, jsrListener.beforeReadCount); + assertEquals(4, jsrListener.afterReadCount); + assertEquals(4, jsrListener.beforeProcessCount); + assertEquals(4, jsrListener.afterProcessCount); + assertEquals(2, jsrListener.beforeWriteCount); + assertEquals(2, jsrListener.afterWriteCount); + } + + @SuppressWarnings("rawtypes") + public static class SpringItemListener implements ItemReadListener, ItemProcessListener, ItemWriteListener { + + protected int beforeReadCount = 0; + protected int afterReadCount = 0; + protected int onReadErrorCount = 0; + protected int beforeProcessCount = 0; + protected int afterProcessCount = 0; + protected int onProcessErrorCount = 0; + protected int beforeWriteCount = 0; + protected int afterWriteCount = 0; + protected int onWriteErrorCount = 0; + + @Override + public void beforeRead() { + beforeReadCount++; + } + + @Override + public void afterRead(Object item) { + afterReadCount++; + } + + @Override + public void onReadError(Exception ex) { + onReadErrorCount++; + } + + @Override + public void beforeWrite(List items) { + beforeWriteCount++; + } + + @Override + public void afterWrite(List items) { + afterWriteCount++; + } + + @Override + public void onWriteError(Exception exception, List items) { + onWriteErrorCount++; + } + + @Override + public void beforeProcess(Object item) { + beforeProcessCount++; + } + + @Override + public void afterProcess(Object item, Object result) { + afterProcessCount++; + } + + @Override + public void onProcessError(Object item, Exception e) { + onProcessErrorCount++; + } + } + + public static class JsrItemListener implements javax.batch.api.chunk.listener.ItemReadListener, javax.batch.api.chunk.listener.ItemProcessListener, javax.batch.api.chunk.listener.ItemWriteListener { + + protected int beforeReadCount = 0; + protected int afterReadCount = 0; + protected int onReadErrorCount = 0; + protected int beforeProcessCount = 0; + protected int afterProcessCount = 0; + protected int onProcessErrorCount = 0; + protected int beforeWriteCount = 0; + protected int afterWriteCount = 0; + protected int onWriteErrorCount = 0; + + @Override + public void beforeWrite(List items) throws Exception { + beforeWriteCount++; + } + + @Override + public void afterWrite(List items) throws Exception { + afterWriteCount++; + } + + @Override + public void onWriteError(List items, Exception ex) + throws Exception { + onWriteErrorCount++; + } + + @Override + public void beforeProcess(Object item) throws Exception { + beforeProcessCount++; + } + + @Override + public void afterProcess(Object item, Object result) throws Exception { + afterProcessCount++; + } + + @Override + public void onProcessError(Object item, Exception ex) throws Exception { + onProcessErrorCount++; + } + + @Override + public void beforeRead() throws Exception { + beforeReadCount++; + } + + @Override + public void afterRead(Object item) throws Exception { + afterReadCount++; + } + + @Override + public void onReadError(Exception ex) throws Exception { + onReadErrorCount++; + } + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests.java index 1228680df..767cccb47 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests.java @@ -1,3 +1,18 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; @@ -5,6 +20,7 @@ import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.List; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; @@ -23,7 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ContextConfiguration({"ItemSkipParsingTests-context.xml", "jsr-base-context.xml"}) +@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class ItemSkipParsingTests { @@ -37,6 +53,7 @@ public class ItemSkipParsingTests { public TestSkipListener skipListener; @Test + @Ignore public void test() throws Exception { // Read skip and fail JobExecution execution = jobLauncher.run(job, new JobParametersBuilder().toJobParameters()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests.java index ed9f61386..c344f9165 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests.java @@ -1,8 +1,25 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import javax.batch.api.listener.JobListener; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; @@ -15,7 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ContextConfiguration({"JobListenerParsingTests-context.xml", "jsr-base-context.xml"}) +@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class JobListenerParsingTests { @@ -26,7 +43,10 @@ public class JobListenerParsingTests { public JobLauncher jobLauncher; @Autowired - public JobListener listener; + public SpringJobListener springListener; + + @Autowired + public JsrJobListener jsrListener; @Test public void test() throws Exception { @@ -36,11 +56,13 @@ public class JobListenerParsingTests { JobExecution execution = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.COMPLETED, execution.getStatus()); assertEquals(2, execution.getStepExecutions().size()); - assertEquals(1, listener.countAfterJob); - assertEquals(1, listener.countBeforeJob); + assertEquals(1, springListener.countAfterJob); + assertEquals(1, springListener.countBeforeJob); + assertEquals(1, jsrListener.countAfterJob); + assertEquals(1, jsrListener.countBeforeJob); } - public static class JobListener implements JobExecutionListener { + public static class SpringJobListener implements JobExecutionListener { protected int countBeforeJob = 0; protected int countAfterJob = 0; @@ -55,4 +77,20 @@ public class JobListenerParsingTests { countAfterJob++; } } + + public static class JsrJobListener implements JobListener { + + protected int countBeforeJob = 0; + protected int countAfterJob = 0; + + @Override + public void afterJob() throws Exception { + countBeforeJob++; + } + + @Override + public void beforeJob() throws Exception { + countAfterJob++; + } + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests.java index 3af73a9fc..79a2b46bf 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests.java @@ -1,3 +1,18 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; @@ -11,7 +26,6 @@ import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.Step; import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.repeat.CompletionPolicy; import org.springframework.batch.repeat.RepeatContext; import org.springframework.batch.repeat.RepeatStatus; @@ -19,7 +33,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ContextConfiguration({"SimpleItemBasedJobParsingTests-context.xml", "jsr-base-context.xml"}) +@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class SimpleItemBasedJobParsingTests { @@ -52,16 +66,6 @@ public class SimpleItemBasedJobParsingTests { assertEquals(3, policy.counter); } - public static class CountingItemProcessor implements ItemProcessor{ - protected int count = 0; - - @Override - public String process(String item) throws Exception { - count++; - return item; - } - } - public static class CountingCompletionPolicy implements CompletionPolicy { protected int counter; diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests.java index 7dd622362..2c1588379 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests.java @@ -3,6 +3,8 @@ package org.springframework.batch.core.jsr.configuration.xml; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import javax.batch.api.Batchlet; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; @@ -16,7 +18,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ContextConfiguration({"SimpleJobParsingTests-context.xml", "jsr-base-context.xml"}) +@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class SimpleJobParsingTests { @@ -38,6 +40,9 @@ public class SimpleJobParsingTests { @Autowired public JobLauncher jobLauncher; + @Autowired + public Batchlet batchlet; + @Test public void test() throws Exception { assertNotNull(job); @@ -48,6 +53,7 @@ public class SimpleJobParsingTests { assertEquals("step2", step2.getName()); assertNotNull(step3); assertEquals("step3", step3.getName()); + assertNotNull(batchlet); JobExecution execution = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.COMPLETED, execution.getStatus()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SplitParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SplitParsingTests.java index 1464cf015..7116ef36c 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SplitParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/SplitParsingTests.java @@ -1,9 +1,25 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -33,6 +49,7 @@ public class SplitParsingTests { public ExpectedException expectedException = ExpectedException.none(); @Test + @Ignore public void test() throws Exception { JobExecution execution = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.COMPLETED, execution.getStatus()); @@ -40,6 +57,7 @@ public class SplitParsingTests { } @Test + @Ignore public void testOneFlowInSplit() { try { new ClassPathXmlApplicationContext("/org/springframework/batch/core/jsr/configuration/xml/invalid-split-context.xml"); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests.java index c24be99a7..974e442d3 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests.java @@ -1,7 +1,24 @@ +/* + * Copyright 2013 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 static org.junit.Assert.assertEquals; +import javax.batch.api.listener.StepListener; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; @@ -16,7 +33,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ContextConfiguration({"StepListenerParsingTests-context.xml", "jsr-base-context.xml"}) +@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class StepListenerParsingTests { @@ -27,18 +44,23 @@ public class StepListenerParsingTests { public JobLauncher jobLauncher; @Autowired - public StepListener stepListener; + public SpringStepListener springStepListener; + + @Autowired + public JsrStepListener jsrStepListener; @Test public void test() throws Exception { JobExecution execution = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.COMPLETED, execution.getStatus()); - assertEquals(2, execution.getStepExecutions().size()); - assertEquals(2, stepListener.countBeforeStep); - assertEquals(2, stepListener.countAfterStep); + assertEquals(3, execution.getStepExecutions().size()); + assertEquals(2, springStepListener.countBeforeStep); + assertEquals(2, springStepListener.countAfterStep); + assertEquals(2, jsrStepListener.countBeforeStep); + assertEquals(2, jsrStepListener.countAfterStep); } - public static class StepListener implements StepExecutionListener { + public static class SpringStepListener implements StepExecutionListener { protected int countBeforeStep = 0; protected int countAfterStep = 0; @@ -53,4 +75,19 @@ public class StepListenerParsingTests { return null; } } + + public static class JsrStepListener implements StepListener { + protected int countBeforeStep = 0; + protected int countAfterStep = 0; + + @Override + public void beforeStep() throws Exception { + countBeforeStep++; + } + + @Override + public void afterStep() throws Exception { + countAfterStep++; + } + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/batchlet/BatchletAdapterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/batchlet/BatchletAdapterTests.java new file mode 100644 index 000000000..fe84ddb6a --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/batchlet/BatchletAdapterTests.java @@ -0,0 +1,53 @@ +package org.springframework.batch.core.jsr.step.batchlet; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.batch.api.Batchlet; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.repeat.RepeatStatus; + +public class BatchletAdapterTests { + + private BatchletAdapter adapter; + @Mock + private Batchlet delegate; + @Mock + private StepContribution contribution; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + adapter = new BatchletAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new BatchletAdapter(null); + } + + @Test + public void testExecuteNoExitStatus() throws Exception { + assertEquals(RepeatStatus.FINISHED, adapter.execute(contribution, null)); + + verify(delegate).process(); + } + + @Test + public void testExecuteWithExitStatus() throws Exception { + when(delegate.process()).thenReturn("my exit status"); + + assertEquals(RepeatStatus.FINISHED, adapter.execute(contribution, null)); + + verify(delegate).process(); + verify(contribution).setExitStatus(new ExitStatus("my exit status")); + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/batchlet/BatchletSupport.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/batchlet/BatchletSupport.java new file mode 100644 index 000000000..e7f0016ad --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/batchlet/BatchletSupport.java @@ -0,0 +1,16 @@ +package org.springframework.batch.core.jsr.step.batchlet; + +import javax.batch.api.Batchlet; + +public class BatchletSupport implements Batchlet { + + @Override + public String process() throws Exception { + return null; + } + + @Override + public void stop() throws Exception { + // no-op + } +} diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ChunkListenerParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ChunkListenerParsingTests-context.xml new file mode 100644 index 000000000..95ad3dcc6 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ChunkListenerParsingTests-context.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + One + Two + + + + + + + + Three + Four + + + + + + + + Five + Six + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml index b54b4db95..e0fa6acd7 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml @@ -1,16 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests-context.xml index 12a25ca1e..bb0d85a6c 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ExceptionHandlingParsingTests-context.xml @@ -1,38 +1,87 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + One + Two + + + + + + + + Three + Four + + + + + + + + Five + Six + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ItemListenerParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ItemListenerParsingTests-context.xml new file mode 100644 index 000000000..af25d3af3 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ItemListenerParsingTests-context.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + One + Two + + + + + + + + Three + Four + + + + + + + + Five + Six + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests-context.xml index 6c5c9919c..12ec243f3 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/ItemSkipParsingTests-context.xml @@ -1,20 +1,39 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests-context.xml index 5ef829ec2..5acf018ba 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/JobListenerParsingTests-context.xml @@ -1,15 +1,33 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests-context.xml index 9b8e6eeef..61b223031 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleItemBasedJobParsingTests-context.xml @@ -1,29 +1,78 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + One + Two + + + + + + + + Three + Four + + + + + + + + Five + Six + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests-context.xml index 36d657924..86f432b94 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/SimpleJobParsingTests-context.xml @@ -1,16 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests-context.xml index 49ea20190..cc4c1ac4c 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/StepListenerParsingTests-context.xml @@ -1,18 +1,42 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/batch.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/batch.xml index 7477deaa7..6c798fdbd 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/batch.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/batch.xml @@ -1,5 +1,3 @@ - + \ No newline at end of file diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/jsr-base-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/jsr-base-context.xml deleted file mode 100644 index 6729d10d2..000000000 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/jsr-base-context.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - One - Two - - - - - - - - Three - Four - - - - - - - - Five - Six - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index 674a1bb4c..5f579e549 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -136,6 +136,12 @@ 1.4 true + + javax.batch + javax.batch-api + provided + true + org.springframework spring-oxm diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemProcessorAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemProcessorAdapter.java new file mode 100644 index 000000000..873b29ede --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemProcessorAdapter.java @@ -0,0 +1,21 @@ +package org.springframework.batch.jsr.item; + +import javax.batch.api.chunk.ItemProcessor; + +import org.springframework.util.Assert; + +@SuppressWarnings("rawtypes") +public class ItemProcessorAdapter implements org.springframework.batch.item.ItemProcessor { + + private ItemProcessor delegate; + + public ItemProcessorAdapter(ItemProcessor processor) { + Assert.notNull(processor, "An ItemProcessor implementation is required"); + this.delegate = processor; + } + + @Override + public Object process(Object item) throws Exception { + return delegate.processItem(item); + } +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemReaderAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemReaderAdapter.java new file mode 100644 index 000000000..5bef0cf8b --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemReaderAdapter.java @@ -0,0 +1,64 @@ +package org.springframework.batch.jsr.item; + +import java.io.Serializable; + +import javax.batch.api.chunk.ItemReader; + +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.ItemStreamSupport; +import org.springframework.batch.item.NonTransientResourceException; +import org.springframework.batch.item.ParseException; +import org.springframework.batch.item.UnexpectedInputException; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +@SuppressWarnings("rawtypes") +public class ItemReaderAdapter extends ItemStreamSupport implements org.springframework.batch.item.ItemReader { + + private static final String CHECKPOINT_KEY = "reader.checkpoint"; + + private ItemReader delegate; + + public ItemReaderAdapter(ItemReader reader) { + Assert.notNull(reader, "An ItemReader implementation is required"); + this.delegate = reader; + setExecutionContextName(ClassUtils.getShortName(delegate.getClass())); + } + + @Override + public void open(ExecutionContext executionContext) + throws ItemStreamException { + try { + delegate.open((Serializable) executionContext.get(getExecutionContextKey(CHECKPOINT_KEY))); + } catch (Exception e) { + throw new ItemStreamException(e); + } + } + + @Override + public void update(ExecutionContext executionContext) + throws ItemStreamException { + try { + Serializable checkpoint = delegate.checkpointInfo(); + executionContext.put(getExecutionContextKey(CHECKPOINT_KEY), checkpoint); + } catch (Exception e) { + throw new ItemStreamException(e); + } + } + + @Override + public void close() throws ItemStreamException { + try { + delegate.close(); + } catch (Exception e) { + throw new ItemStreamException(e); + } + } + + @Override + public Object read() throws Exception, UnexpectedInputException, ParseException, + NonTransientResourceException { + return delegate.readItem(); + } +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemWriterAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemWriterAdapter.java new file mode 100644 index 000000000..fc54b7f21 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/item/ItemWriterAdapter.java @@ -0,0 +1,62 @@ +package org.springframework.batch.jsr.item; + +import java.io.Serializable; +import java.util.List; + +import javax.batch.api.chunk.ItemWriter; + +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.ItemStreamSupport; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +@SuppressWarnings("rawtypes") +public class ItemWriterAdapter extends ItemStreamSupport implements org.springframework.batch.item.ItemWriter { + + private static final String CHECKPOINT_KEY = "writer.checkpoint"; + + private ItemWriter delegate; + + public ItemWriterAdapter(ItemWriter writer) { + Assert.notNull(writer, "An ItemWriter implementation is required"); + this.delegate = writer; + super.setExecutionContextName(ClassUtils.getShortName(delegate.getClass())); + } + + @Override + public void open(ExecutionContext executionContext) + throws ItemStreamException { + try { + delegate.open((Serializable) executionContext.get(getExecutionContextKey(CHECKPOINT_KEY))); + } catch (Exception e) { + throw new ItemStreamException(e); + } + } + + @Override + public void update(ExecutionContext executionContext) + throws ItemStreamException { + try { + Serializable checkpoint = delegate.checkpointInfo(); + executionContext.put(getExecutionContextKey(CHECKPOINT_KEY), checkpoint); + } catch (Exception e) { + throw new ItemStreamException(e); + } + } + + @Override + public void close() throws ItemStreamException { + try { + delegate.close(); + } catch (Exception e) { + throw new ItemStreamException(e); + } + } + + @Override + @SuppressWarnings("unchecked") + public void write(List items) throws Exception { + delegate.writeItems(items); + } +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/repeat/CheckpointAlgorithmAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/repeat/CheckpointAlgorithmAdapter.java new file mode 100644 index 000000000..4416ef7df --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/jsr/repeat/CheckpointAlgorithmAdapter.java @@ -0,0 +1,63 @@ +package org.springframework.batch.jsr.repeat; + +import javax.batch.api.chunk.CheckpointAlgorithm; + +import org.springframework.batch.repeat.CompletionPolicy; +import org.springframework.batch.repeat.RepeatContext; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.util.Assert; + +public class CheckpointAlgorithmAdapter implements CompletionPolicy { + + private CheckpointAlgorithm policy; + + public CheckpointAlgorithmAdapter(CheckpointAlgorithm policy) { + Assert.notNull(policy, "A CheckpointAlgorithm is required"); + + this.policy = policy; + } + + @Override + public boolean isComplete(RepeatContext context, RepeatStatus result) { + try { + return policy.isReadyToCheckpoint(); + } catch (Exception e) { + //TODO: do something here + } + + return false; + } + + @Override + public boolean isComplete(RepeatContext context) { + try { + return policy.isReadyToCheckpoint(); + } catch (Exception e) { + //TODO: do something here + } + + return false; + } + + @Override + public RepeatContext start(RepeatContext parent) { + try { + policy.beginCheckpoint(); + } catch (Exception e) { + //TODO: do something here + } + + return null; + } + + @Override + public void update(RepeatContext context) { + try { + if(policy.isReadyToCheckpoint()) { + policy.endCheckpoint(); + } + } catch (Exception e) { + //TODO: do something here + } + } +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemProcessorAdapterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemProcessorAdapterTests.java new file mode 100644 index 000000000..70b44bfbb --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemProcessorAdapterTests.java @@ -0,0 +1,40 @@ +package org.springframework.batch.jsr.item; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import javax.batch.api.chunk.ItemProcessor; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class ItemProcessorAdapterTests { + + private ItemProcessorAdapter adapter; + @Mock + private ItemProcessor delegate; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + adapter = new ItemProcessorAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new ItemProcessorAdapter(null); + } + + @Test + public void testProcess() throws Exception { + String input = "input"; + String output = "output"; + + when(delegate.processItem(input)).thenReturn(output); + + assertEquals(output, adapter.process(input)); + } +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemReaderAdapterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemReaderAdapterTests.java new file mode 100644 index 000000000..9f9e4e95c --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemReaderAdapterTests.java @@ -0,0 +1,91 @@ +package org.springframework.batch.jsr.item; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.batch.api.chunk.ItemReader; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStreamException; + +public class ItemReaderAdapterTests { + + private ItemReaderAdapter adapter; + @Mock + private ItemReader delegate; + @Mock + private ExecutionContext executionContext; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + adapter = new ItemReaderAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new ItemReaderAdapter(null); + } + + @Test + public void testOpen() throws Exception { + when(executionContext.get("ItemReader.reader.checkpoint")).thenReturn("checkpoint"); + + adapter.open(executionContext); + + verify(delegate).open("checkpoint"); + } + + @Test(expected=ItemStreamException.class) + public void testOpenException() throws Exception { + when(executionContext.get("ItemReader.reader.checkpoint")).thenReturn("checkpoint"); + + doThrow(new Exception("expected")).when(delegate).open("checkpoint"); + + adapter.open(executionContext); + } + + @Test + public void testUpdate() throws Exception { + when(delegate.checkpointInfo()).thenReturn("checkpoint"); + + adapter.update(executionContext); + + verify(executionContext).put("ItemReader.reader.checkpoint", "checkpoint"); + } + + @Test(expected=ItemStreamException.class) + public void testUpdateException() throws Exception { + doThrow(new Exception("expected")).when(delegate).checkpointInfo(); + + adapter.update(executionContext); + } + + @Test + public void testClose() throws Exception { + adapter.close(); + + verify(delegate).close(); + } + + @Test(expected=ItemStreamException.class) + public void testCloseException() throws Exception { + doThrow(new Exception("expected")).when(delegate).close(); + + adapter.close(); + } + + @Test + public void testRead() throws Exception { + when(delegate.readItem()).thenReturn("item"); + + assertEquals("item", adapter.read()); + } +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemWriterAdapterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemWriterAdapterTests.java new file mode 100644 index 000000000..248281703 --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/jsr/item/ItemWriterAdapterTests.java @@ -0,0 +1,99 @@ +package org.springframework.batch.jsr.item; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import javax.batch.api.chunk.ItemWriter; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStreamException; + +public class ItemWriterAdapterTests { + + private ItemWriterAdapter adapter; + @Mock + private ItemWriter delegate; + @Mock + private ExecutionContext executionContext; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + adapter = new ItemWriterAdapter(delegate); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateWithNull() { + adapter = new ItemWriterAdapter(null); + } + + @Test + public void testOpen() throws Exception { + when(executionContext.get("ItemWriter.writer.checkpoint")).thenReturn("checkpoint"); + + adapter.open(executionContext); + + verify(delegate).open("checkpoint"); + } + + @Test(expected=ItemStreamException.class) + public void testOpenException() throws Exception { + when(executionContext.get("ItemWriter.writer.checkpoint")).thenReturn("checkpoint"); + + doThrow(new Exception("expected")).when(delegate).open("checkpoint"); + + adapter.open(executionContext); + } + + @Test + public void testUpdate() throws Exception { + when(delegate.checkpointInfo()).thenReturn("checkpoint"); + + adapter.update(executionContext); + + verify(executionContext).put("ItemWriter.writer.checkpoint", "checkpoint"); + } + + @Test(expected=ItemStreamException.class) + public void testUpdateException() throws Exception { + doThrow(new Exception("expected")).when(delegate).checkpointInfo(); + + adapter.update(executionContext); + } + + @Test + public void testClose() throws Exception { + adapter.close(); + + verify(delegate).close(); + } + + @Test(expected=ItemStreamException.class) + public void testCloseException() throws Exception { + doThrow(new Exception("expected")).when(delegate).close(); + + adapter.close(); + } + + @Test + @SuppressWarnings({"rawtypes", "unchecked"}) + public void testWrite() throws Exception { + List items = new ArrayList(); + + items.add("item1"); + items.add("item2"); + + adapter.write(items); + + verify(delegate).writeItems(items); + } +} diff --git a/spring-batch-parent/pom.xml b/spring-batch-parent/pom.xml index e5ba7a661..89f9f8900 100644 --- a/spring-batch-parent/pom.xml +++ b/spring-batch-parent/pom.xml @@ -599,6 +599,13 @@ provided true + + javax.batch + javax.batch-api + 1.0 + provided + true + stax stax