@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2020 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -250,22 +250,6 @@ public class JobExecution extends Entity {
|
||||
return status == BatchStatus.STOPPING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal the {@link JobExecution} to stop. Iterates through the associated
|
||||
* {@link StepExecution}s, calling {@link StepExecution#setTerminateOnly()}.
|
||||
*
|
||||
* @deprecated Use {@link org.springframework.batch.core.launch.JobOperator#stop(long)}
|
||||
* or {@link org.springframework.batch.core.launch.support.CommandLineJobRunner}
|
||||
* with the "-stop" option instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void stop() {
|
||||
for (StepExecution stepExecution : stepExecutions) {
|
||||
stepExecution.setTerminateOnly();
|
||||
}
|
||||
status = BatchStatus.STOPPING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ExecutionContext} for this execution
|
||||
*
|
||||
|
||||
@@ -70,27 +70,6 @@ public class JobParameters implements Serializable {
|
||||
return value==null ? null : ((Long)value).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Typesafe Getter for the Long represented by the provided key. If the
|
||||
* key does not exist, the default value will be returned.
|
||||
*
|
||||
* @param key to return the value for
|
||||
* @param defaultValue to return if the value doesn't exist
|
||||
* @return the parameter represented by the provided key, defaultValue
|
||||
* otherwise.
|
||||
* @deprecated Use {@link JobParameters#getLong(java.lang.String, java.lang.Long)}
|
||||
* instead. This method will be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public Long getLong(String key, long defaultValue){
|
||||
if(parameters.containsKey(key)){
|
||||
return getLong(key);
|
||||
}
|
||||
else{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Typesafe Getter for the Long represented by the provided key. If the
|
||||
* key does not exist, the default value will be returned.
|
||||
@@ -156,27 +135,6 @@ public class JobParameters implements Serializable {
|
||||
return value==null ? null : value.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Typesafe Getter for the Double represented by the provided key. If the
|
||||
* key does not exist, the default value will be returned.
|
||||
*
|
||||
* @param key to return the value for
|
||||
* @param defaultValue to return if the value doesn't exist
|
||||
* @return the parameter represented by the provided key, defaultValue
|
||||
* otherwise.
|
||||
* @deprecated Use {@link JobParameters#getDouble(java.lang.String, java.lang.Double)}
|
||||
* instead. This method will be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public Double getDouble(String key, double defaultValue){
|
||||
if(parameters.containsKey(key)){
|
||||
return getDouble(key);
|
||||
}
|
||||
else{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Typesafe Getter for the Double represented by the provided key. If the
|
||||
* key does not exist, the default value will be returned.
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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
|
||||
*
|
||||
* https://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.configuration.support;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* {@link ApplicationContextFactory} implementation that takes a parent context
|
||||
* and a path to the context to create. When createApplicationContext method is
|
||||
* called, the child {@link ApplicationContext} will be returned. The child
|
||||
* context is not re-created every time it is requested, it is lazily
|
||||
* initialized and cached. Clients should ensure that it is closed when it is no
|
||||
* longer needed. If a path is not set, the parent will always be returned.
|
||||
*
|
||||
* @deprecated use {@link GenericApplicationContextFactory} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class ClassPathXmlApplicationContextFactory extends GenericApplicationContextFactory {
|
||||
|
||||
/**
|
||||
* Create an application context factory for the resource specified.
|
||||
*
|
||||
* @param resource a resource (XML configuration file)
|
||||
*/
|
||||
public ClassPathXmlApplicationContextFactory(Resource resource) {
|
||||
super(resource);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008-2010 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
|
||||
*
|
||||
* https://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.configuration.support;
|
||||
|
||||
/**
|
||||
* Placeholder for deprecation warning.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @deprecated in version 2.1, please us {@link AutomaticJobRegistrar} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class ClassPathXmlJobRegistry {
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2020 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
|
||||
*
|
||||
* https://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.launch.support;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.batch.core.JobParameter;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.converter.JobParametersConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
* @deprecated as of v4.3 in favor of
|
||||
* {@link org.springframework.batch.core.converter.DefaultJobParametersConverter}
|
||||
* and scheduled for removal in v5.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ScheduledJobParametersFactory implements JobParametersConverter {
|
||||
|
||||
public static final String SCHEDULE_DATE_KEY = "schedule.date";
|
||||
|
||||
private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.batch.core.runtime.JobParametersFactory#getJobParameters(java.util.Properties)
|
||||
*/
|
||||
@Override
|
||||
public JobParameters getJobParameters(@Nullable Properties props) {
|
||||
|
||||
if (props == null || props.isEmpty()) {
|
||||
return new JobParameters();
|
||||
}
|
||||
|
||||
JobParametersBuilder propertiesBuilder = new JobParametersBuilder();
|
||||
|
||||
for (Entry<Object, Object> entry : props.entrySet()) {
|
||||
if (entry.getKey().equals(SCHEDULE_DATE_KEY)) {
|
||||
Date scheduleDate;
|
||||
try {
|
||||
scheduleDate = dateFormat.parse(entry.getValue().toString());
|
||||
} catch (ParseException ex) {
|
||||
throw new IllegalArgumentException("Date format is invalid: [" + entry.getValue() + "]");
|
||||
}
|
||||
propertiesBuilder.addDate(entry.getKey().toString(), scheduleDate);
|
||||
} else {
|
||||
propertiesBuilder.addString(entry.getKey().toString(), entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return propertiesBuilder.toJobParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert schedule date to Date, and assume all other parameters can be represented by their default string value.
|
||||
*
|
||||
* @see org.springframework.batch.core.converter.JobParametersConverter#getProperties(org.springframework.batch.core.JobParameters)
|
||||
*/
|
||||
@Override
|
||||
public Properties getProperties(@Nullable JobParameters params) {
|
||||
|
||||
if (params == null || params.isEmpty()) {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
Map<String, JobParameter> parameters = params.getParameters();
|
||||
Properties result = new Properties();
|
||||
for (Entry<String, JobParameter> entry : parameters.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
JobParameter jobParameter = entry.getValue();
|
||||
if (key.equals(SCHEDULE_DATE_KEY)) {
|
||||
result.setProperty(key, dateFormat.format(jobParameter.getValue()));
|
||||
} else {
|
||||
result.setProperty(key, "" + jobParameter.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for injecting a date format.
|
||||
*
|
||||
* @param dateFormat a {@link DateFormat}, defaults to "yyyy/MM/dd"
|
||||
*/
|
||||
public void setDateFormat(DateFormat dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2018 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -84,26 +84,6 @@ public class SimpleStepExecutionSplitter implements StepExecutionSplitter, Initi
|
||||
this.stepName = stepName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link SimpleStepExecutionSplitter} from its mandatory
|
||||
* properties.
|
||||
*
|
||||
* @param jobRepository the {@link JobRepository}
|
||||
* @param step the target step (a local version of it), used to extract the
|
||||
* name and allowStartIfComplete flags
|
||||
* @param partitioner a {@link Partitioner} to use for generating input
|
||||
* parameters
|
||||
*
|
||||
* @deprecated use {@link #SimpleStepExecutionSplitter(JobRepository, boolean, String, Partitioner)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleStepExecutionSplitter(JobRepository jobRepository, Step step, Partitioner partitioner) {
|
||||
this.jobRepository = jobRepository;
|
||||
this.allowStartIfComplete = step.isAllowStartIfComplete();
|
||||
this.partitioner = partitioner;
|
||||
this.stepName = step.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check mandatory properties (step name, job repository and partitioner).
|
||||
*
|
||||
@@ -247,22 +227,6 @@ public class SimpleStepExecutionSplitter implements StepExecutionSplitter, Initi
|
||||
* @throws JobExecutionException if unable to check if the step execution is startable
|
||||
*/
|
||||
protected boolean isStartable(StepExecution stepExecution, ExecutionContext context) throws JobExecutionException {
|
||||
return getStartable(stepExecution, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a step execution is startable.
|
||||
* @param stepExecution the step execution to check
|
||||
* @param context the execution context of the step
|
||||
* @return true if the step execution is startable, false otherwise
|
||||
* @throws JobExecutionException if unable to check if the step execution is startable
|
||||
* @deprecated This method is deprecated in favor of
|
||||
* {@link SimpleStepExecutionSplitter#isStartable} and will be removed in a
|
||||
* future version.
|
||||
*/
|
||||
@Deprecated
|
||||
protected boolean getStartable(StepExecution stepExecution, ExecutionContext context) throws JobExecutionException {
|
||||
|
||||
JobInstance jobInstance = stepExecution.getJobExecution().getJobInstance();
|
||||
String stepName = stepExecution.getStepName();
|
||||
StepExecution lastStepExecution = jobRepository.getLastStepExecution(jobInstance, stepName);
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2018 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
|
||||
*
|
||||
* https://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.repository.dao;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
|
||||
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
|
||||
|
||||
import org.springframework.batch.core.repository.ExecutionContextSerializer;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.serializer.Deserializer;
|
||||
import org.springframework.core.serializer.Serializer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation that uses XStream and Jettison to provide serialization.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Michael Minella
|
||||
* @author Mahmoud Ben Hassine
|
||||
* @since 2.0
|
||||
* @see ExecutionContextSerializer
|
||||
* @deprecated Due to the incompatibilities between current Jettison versions and XStream
|
||||
* versions, this serializer is deprecated in favor of
|
||||
* {@link Jackson2ExecutionContextStringSerializer}
|
||||
*/
|
||||
@Deprecated
|
||||
public class XStreamExecutionContextStringSerializer implements ExecutionContextSerializer, InitializingBean {
|
||||
|
||||
private ReflectionProvider reflectionProvider = null;
|
||||
|
||||
private HierarchicalStreamDriver hierarchicalStreamDriver;
|
||||
|
||||
private XStream xstream;
|
||||
|
||||
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
|
||||
this.reflectionProvider = reflectionProvider;
|
||||
}
|
||||
|
||||
public void setHierarchicalStreamDriver(HierarchicalStreamDriver hierarchicalStreamDriver) {
|
||||
this.hierarchicalStreamDriver = hierarchicalStreamDriver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
init();
|
||||
}
|
||||
|
||||
public synchronized void init() throws Exception {
|
||||
if (hierarchicalStreamDriver == null) {
|
||||
this.hierarchicalStreamDriver = new JettisonMappedXmlDriver();
|
||||
}
|
||||
if (reflectionProvider == null) {
|
||||
xstream = new XStream(hierarchicalStreamDriver);
|
||||
}
|
||||
else {
|
||||
xstream = new XStream(reflectionProvider, hierarchicalStreamDriver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the passed execution context to the supplied OutputStream.
|
||||
*
|
||||
* @param context {@link Map} containing the context information.
|
||||
* @param out {@link OutputStream} where the serialized context information
|
||||
* will be written.
|
||||
*
|
||||
* @see Serializer#serialize(Object, OutputStream)
|
||||
*/
|
||||
@Override
|
||||
public void serialize(Map<String, Object> context, OutputStream out) throws IOException {
|
||||
Assert.notNull(context, "context is required");
|
||||
Assert.notNull(out, "An OutputStream is required");
|
||||
|
||||
out.write(xstream.toXML(context).getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the supplied input stream into a new execution context.
|
||||
*
|
||||
* @param in {@link InputStream} containing the information to be deserialized.
|
||||
|
||||
* @return a reconstructed execution context
|
||||
* @see Deserializer#deserialize(InputStream)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> deserialize(InputStream in) throws IOException {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
|
||||
return (Map<String, Object>) xstream.fromXML(sb.toString());
|
||||
}
|
||||
}
|
||||
@@ -72,19 +72,6 @@ public class JobExecutionTests {
|
||||
assertFalse(execution.isRunning());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.batch.core.JobExecution#getEndTime()}.
|
||||
*/
|
||||
@Test
|
||||
public void testIsRunningWithStoppedExecution() {
|
||||
execution.setStartTime(new Date());
|
||||
assertTrue(execution.isRunning());
|
||||
execution.stop();
|
||||
assertTrue(execution.isRunning());
|
||||
assertTrue(execution.isStopping());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.batch.core.JobExecution#getStartTime()}.
|
||||
@@ -206,14 +193,6 @@ public class JobExecutionTests {
|
||||
assertEquals(2, execution.getStepExecutions().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStop() throws Exception {
|
||||
StepExecution stepExecution = execution.createStepExecution("step");
|
||||
assertFalse(stepExecution.isTerminateOnly());
|
||||
execution.stop();
|
||||
assertTrue(stepExecution.isTerminateOnly());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() throws Exception {
|
||||
assertTrue("JobExecution string does not contain id", execution.toString().indexOf("id=") >= 0);
|
||||
|
||||
@@ -102,7 +102,6 @@ public class SimpleJobTests {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
EmbeddedDatabase embeddedDatabase = new EmbeddedDatabaseBuilder()
|
||||
.addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
|
||||
.addScript("/org/springframework/batch/core/schema-hsqldb.sql")
|
||||
@@ -394,17 +393,6 @@ public class SimpleJobTests {
|
||||
"no steps configured") >= 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotExecutedIfAlreadyStopped() throws Exception {
|
||||
jobExecution.stop();
|
||||
job.execute(jobExecution);
|
||||
|
||||
assertEquals(0, list.size());
|
||||
checkRepository(BatchStatus.STOPPED, ExitStatus.NOOP);
|
||||
ExitStatus exitStatus = jobExecution.getExitStatus();
|
||||
assertEquals(ExitStatus.NOOP.getExitCode(), exitStatus.getExitCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestart() throws Exception {
|
||||
step1.setAllowStartIfComplete(true);
|
||||
@@ -493,31 +481,6 @@ public class SimpleJobTests {
|
||||
assertFalse(step2.passedInJobContext.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterruptJob() throws Exception {
|
||||
|
||||
step1 = new StubStep("interruptStep", jobRepository) {
|
||||
|
||||
@Override
|
||||
public void execute(StepExecution stepExecution) throws JobInterruptedException,
|
||||
UnexpectedJobExecutionException {
|
||||
stepExecution.getJobExecution().stop();
|
||||
super.execute(stepExecution);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
job.setSteps(Arrays.asList(new Step[] { step1, step2 }));
|
||||
job.execute(jobExecution);
|
||||
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
|
||||
assertEquals(1, jobExecution.getAllFailureExceptions().size());
|
||||
Throwable expected = jobExecution.getAllFailureExceptions().get(0);
|
||||
assertTrue("Wrong exception " + expected, expected instanceof JobInterruptedException);
|
||||
assertEquals("JobExecution interrupted.", expected.getMessage());
|
||||
|
||||
assertNull("Second step was not supposed to be executed", step2.passedInStepContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStepExists() {
|
||||
step1 = new StubStep("step1", jobRepository);
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-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
|
||||
*
|
||||
* https://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.launch.support;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
public class ScheduledJobParametersFactoryTests extends TestCase {
|
||||
|
||||
ScheduledJobParametersFactory factory;
|
||||
|
||||
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
factory = new ScheduledJobParametersFactory();
|
||||
}
|
||||
|
||||
public void testGetParameters() throws Exception {
|
||||
|
||||
String jobKey = "job.key=myKey";
|
||||
String scheduleDate = "schedule.date=2008/01/23";
|
||||
String vendorId = "vendor.id=33243243";
|
||||
|
||||
String[] args = new String[] { jobKey, scheduleDate, vendorId };
|
||||
|
||||
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
|
||||
assertNotNull(props);
|
||||
assertEquals("myKey", props.getString("job.key"));
|
||||
assertEquals("33243243", props.getString("vendor.id"));
|
||||
Date date = dateFormat.parse("01/23/2008");
|
||||
assertEquals(date, props.getDate("schedule.date"));
|
||||
}
|
||||
|
||||
public void testGetProperties() throws Exception {
|
||||
|
||||
JobParameters parameters = new JobParametersBuilder().addDate("schedule.date", dateFormat.parse("01/23/2008"))
|
||||
.addString("job.key", "myKey").addString("vendor.id", "33243243").toJobParameters();
|
||||
|
||||
Properties props = factory.getProperties(parameters);
|
||||
assertNotNull(props);
|
||||
assertEquals("myKey", props.getProperty("job.key"));
|
||||
assertEquals("33243243", props.getProperty("vendor.id"));
|
||||
assertEquals("2008/01/23", props.getProperty("schedule.date"));
|
||||
}
|
||||
|
||||
public void testEmptyArgs() {
|
||||
|
||||
JobParameters props = factory.getJobParameters(new Properties());
|
||||
assertTrue(props.getParameters().isEmpty());
|
||||
}
|
||||
|
||||
public void testNullArgs() {
|
||||
assertEquals(new JobParameters(), factory.getJobParameters(null));
|
||||
assertEquals(new Properties(), factory.getProperties(null));
|
||||
}
|
||||
|
||||
public void testGetParametersWithDateFormat() throws Exception {
|
||||
|
||||
String[] args = new String[] { "schedule.date=2008/23/01" };
|
||||
|
||||
factory.setDateFormat(new SimpleDateFormat("yyyy/dd/MM"));
|
||||
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
|
||||
assertNotNull(props);
|
||||
Date date = dateFormat.parse("01/23/2008");
|
||||
assertEquals(date, props.getDate("schedule.date"));
|
||||
}
|
||||
|
||||
public void testGetParametersWithBogusDate() throws Exception {
|
||||
|
||||
String[] args = new String[] { "schedule.date=20080123" };
|
||||
|
||||
try {
|
||||
factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
|
||||
} catch (IllegalArgumentException e) {
|
||||
String message = e.getMessage();
|
||||
assertTrue("Message should contain wrong date: " + message, contains(message, "20080123"));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean contains(String str, String searchStr) {
|
||||
return str.indexOf(searchStr) != -1;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008-2016 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
|
||||
*
|
||||
* https://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.repository.dao;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.springframework.batch.core.repository.ExecutionContextSerializer;
|
||||
|
||||
/**
|
||||
* @author Thomas Risberg
|
||||
* @author Michael Minella
|
||||
*/
|
||||
public class XStreamExecutionContextStringSerializerTests extends AbstractExecutionContextSerializerTests {
|
||||
|
||||
ExecutionContextSerializer serializer;
|
||||
|
||||
@Before
|
||||
public void onSetUp() throws Exception {
|
||||
@SuppressWarnings("deprecation")
|
||||
XStreamExecutionContextStringSerializer serializerDeserializer = new XStreamExecutionContextStringSerializer();
|
||||
(serializerDeserializer).afterPropertiesSet();
|
||||
|
||||
serializer = serializerDeserializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExecutionContextSerializer getSerializer() {
|
||||
return this.serializer;
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-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
|
||||
*
|
||||
* https://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.resource;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.job.AbstractJob;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.database.support.ListPreparedStatementSetter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {
|
||||
"/org/springframework/batch/core/resource/ListPreparedStatementSetterTests-context.xml",
|
||||
"/org/springframework/batch/core/repository/dao/data-source-context.xml" })
|
||||
public class ListPreparedStatementSetterTests {
|
||||
|
||||
ListPreparedStatementSetter pss;
|
||||
|
||||
StepExecution stepExecution;
|
||||
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private AbstractJob job;
|
||||
|
||||
@Autowired
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Autowired
|
||||
private FooStoringItemWriter fooStoringItemWriter;
|
||||
|
||||
@Before
|
||||
public void onSetUpInTransaction() throws Exception {
|
||||
|
||||
List<Long> parameters = new ArrayList<>();
|
||||
parameters.add(1L);
|
||||
parameters.add(4L);
|
||||
pss = new ListPreparedStatementSetter(parameters);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
public void testSetValues() {
|
||||
|
||||
final List<String> results = new ArrayList<>();
|
||||
jdbcTemplate.query("SELECT NAME from T_FOOS where ID > ? and ID < ?", pss,
|
||||
new RowCallbackHandler() {
|
||||
@Override
|
||||
public void processRow(ResultSet rs) throws SQLException {
|
||||
results.add(rs.getString(1));
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals(2, results.size());
|
||||
assertEquals("bar2", results.get(0));
|
||||
assertEquals("bar3", results.get(1));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testAfterPropertiesSet() throws Exception {
|
||||
pss = new ListPreparedStatementSetter(null);
|
||||
pss.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlConfiguration() throws Exception {
|
||||
this.jdbcTemplate.update("create table FOO (ID integer, NAME varchar(40), VALUE integer)");
|
||||
try {
|
||||
this.jdbcTemplate.update("insert into FOO values (?,?,?)", 0, "zero", 0);
|
||||
this.jdbcTemplate.update("insert into FOO values (?,?,?)", 1, "one", 1);
|
||||
this.jdbcTemplate.update("insert into FOO values (?,?,?)", 2, "two", 2);
|
||||
this.jdbcTemplate.update("insert into FOO values (?,?,?)", 3, "three", 3);
|
||||
|
||||
JobParametersBuilder builder = new JobParametersBuilder().addLong("min.id", 1L).addLong("max.id", 2L);
|
||||
JobExecution jobExecution = this.jobLauncher.run(this.job, builder.toJobParameters());
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
|
||||
List<Foo> foos = fooStoringItemWriter.getFoos();
|
||||
assertEquals(2, foos.size());
|
||||
System.err.println(foos.get(0));
|
||||
System.err.println(foos.get(1));
|
||||
assertEquals(new Foo(1, "one", 1), foos.get(0));
|
||||
assertEquals(new Foo(2, "two", 2), foos.get(1));
|
||||
}
|
||||
finally {
|
||||
this.jdbcTemplate.update("drop table FOO");
|
||||
}
|
||||
}
|
||||
|
||||
public static class FooStoringItemWriter implements ItemWriter<Foo> {
|
||||
private List<Foo> foos = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void write(List<? extends Foo> items) throws Exception {
|
||||
foos.addAll(items);
|
||||
}
|
||||
|
||||
public List<Foo> getFoos() {
|
||||
return foos;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,5 +35,5 @@
|
||||
<constructor-arg ref="dataSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="serializer" class="org.springframework.batch.core.repository.dao.XStreamExecutionContextStringSerializer"/>
|
||||
<bean id="serializer" class="org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer"/>
|
||||
</beans>
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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
|
||||
*
|
||||
* https://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.item.data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Restartable {@link ItemReader} that reads objects from the graph database Neo4j
|
||||
* via a paging technique.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It executes cypher queries built from the statement fragments provided to
|
||||
* retrieve the requested data. The query is executed using paged requests of
|
||||
* a size specified in {@link #setPageSize(int)}. Additional pages are requested
|
||||
* as needed when the {@link #read()} method is called. On restart, the reader
|
||||
* will begin again at the same number item it left off at.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Performance is dependent on your Neo4J configuration (embedded or remote) as
|
||||
* well as page size. Setting a fairly large page size and using a commit
|
||||
* interval that matches the page size should provide better performance.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This implementation is thread-safe between calls to
|
||||
* {@link #open(org.springframework.batch.item.ExecutionContext)}, however you
|
||||
* should set <code>saveState=false</code> if used in a multi-threaded
|
||||
* environment (no restart available).
|
||||
* </p>
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @author Mahmoud Ben Hassine
|
||||
* @since 3.07
|
||||
* @deprecated Extend {@link Neo4jItemReader} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractNeo4jItemReader<T> extends
|
||||
AbstractPaginatedDataItemReader<T> implements InitializingBean {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private String startStatement;
|
||||
private String returnStatement;
|
||||
private String matchStatement;
|
||||
private String whereStatement;
|
||||
private String orderByStatement;
|
||||
|
||||
private Class<T> targetType;
|
||||
|
||||
private Map<String, Object> parameterValues;
|
||||
|
||||
/**
|
||||
* Optional parameters to be used in the cypher query.
|
||||
*
|
||||
* @param parameterValues the parameter values to be used in the cypher query
|
||||
*/
|
||||
public void setParameterValues(Map<String, Object> parameterValues) {
|
||||
this.parameterValues = parameterValues;
|
||||
}
|
||||
|
||||
protected final Map<String, Object> getParameterValues() {
|
||||
return this.parameterValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* The start segment of the cypher query. START is prepended
|
||||
* to the statement provided and should <em>not</em> be
|
||||
* included.
|
||||
*
|
||||
* @param startStatement the start fragment of the cypher query.
|
||||
*/
|
||||
public void setStartStatement(String startStatement) {
|
||||
this.startStatement = startStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* The return statement of the cypher query. RETURN is prepended
|
||||
* to the statement provided and should <em>not</em> be
|
||||
* included
|
||||
*
|
||||
* @param returnStatement the return fragment of the cypher query.
|
||||
*/
|
||||
public void setReturnStatement(String returnStatement) {
|
||||
this.returnStatement = returnStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional match fragment of the cypher query. MATCH is
|
||||
* prepended to the statement provided and should <em>not</em>
|
||||
* be included.
|
||||
*
|
||||
* @param matchStatement the match fragment of the cypher query
|
||||
*/
|
||||
public void setMatchStatement(String matchStatement) {
|
||||
this.matchStatement = matchStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional where fragment of the cypher query. WHERE is
|
||||
* prepended to the statement provided and should <em>not</em>
|
||||
* be included.
|
||||
*
|
||||
* @param whereStatement where fragment of the cypher query
|
||||
*/
|
||||
public void setWhereStatement(String whereStatement) {
|
||||
this.whereStatement = whereStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of properties to order the results by. This is
|
||||
* required so that subsequent page requests pull back the
|
||||
* segment of results correctly. ORDER BY is prepended to
|
||||
* the statement provided and should <em>not</em> be included.
|
||||
*
|
||||
* @param orderByStatement order by fragment of the cypher query.
|
||||
*/
|
||||
public void setOrderByStatement(String orderByStatement) {
|
||||
this.orderByStatement = orderByStatement;
|
||||
}
|
||||
|
||||
protected SessionFactory getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the session factory for the reader.
|
||||
* @param sessionFactory the factory to use for the reader.
|
||||
*/
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object type to be returned from each call to {@link #read()}
|
||||
*
|
||||
* @param targetType the type of object to return.
|
||||
*/
|
||||
public void setTargetType(Class<T> targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
protected final Class<T> getTargetType() {
|
||||
return this.targetType;
|
||||
}
|
||||
|
||||
protected String generateLimitCypherQuery() {
|
||||
StringBuilder query = new StringBuilder(128);
|
||||
|
||||
query.append("START ").append(startStatement);
|
||||
query.append(matchStatement != null ? " MATCH " + matchStatement : "");
|
||||
query.append(whereStatement != null ? " WHERE " + whereStatement : "");
|
||||
query.append(" RETURN ").append(returnStatement);
|
||||
query.append(" ORDER BY ").append(orderByStatement);
|
||||
query.append(" SKIP " + (pageSize * page));
|
||||
query.append(" LIMIT " + pageSize);
|
||||
|
||||
String resultingQuery = query.toString();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(resultingQuery);
|
||||
}
|
||||
|
||||
return resultingQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks mandatory properties
|
||||
*
|
||||
* @see InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(sessionFactory != null,"A SessionFactory is required");
|
||||
Assert.state(targetType != null, "The type to be returned is required");
|
||||
Assert.state(StringUtils.hasText(startStatement), "A START statement is required");
|
||||
Assert.state(StringUtils.hasText(returnStatement), "A RETURN statement is required");
|
||||
Assert.state(StringUtils.hasText(orderByStatement), "A ORDER BY statement is required");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -18,17 +18,191 @@ package org.springframework.batch.item.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.neo4j.ogm.session.Session;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Extensions of the {@link AbstractNeo4jItemReader}.
|
||||
* Restartable {@link ItemReader} that reads objects from the graph database Neo4j
|
||||
* via a paging technique.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It executes cypher queries built from the statement fragments provided to
|
||||
* retrieve the requested data. The query is executed using paged requests of
|
||||
* a size specified in {@link #setPageSize(int)}. Additional pages are requested
|
||||
* as needed when the {@link #read()} method is called. On restart, the reader
|
||||
* will begin again at the same number item it left off at.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Performance is dependent on your Neo4J configuration (embedded or remote) as
|
||||
* well as page size. Setting a fairly large page size and using a commit
|
||||
* interval that matches the page size should provide better performance.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This implementation is thread-safe between calls to
|
||||
* {@link #open(org.springframework.batch.item.ExecutionContext)}, however you
|
||||
* should set <code>saveState=false</code> if used in a multi-threaded
|
||||
* environment (no restart available).
|
||||
* </p>
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
public class Neo4jItemReader<T> extends AbstractNeo4jItemReader<T> {
|
||||
public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> implements InitializingBean {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private String startStatement;
|
||||
private String returnStatement;
|
||||
private String matchStatement;
|
||||
private String whereStatement;
|
||||
private String orderByStatement;
|
||||
|
||||
private Class<T> targetType;
|
||||
|
||||
private Map<String, Object> parameterValues;
|
||||
|
||||
/**
|
||||
* Optional parameters to be used in the cypher query.
|
||||
*
|
||||
* @param parameterValues the parameter values to be used in the cypher query
|
||||
*/
|
||||
public void setParameterValues(Map<String, Object> parameterValues) {
|
||||
this.parameterValues = parameterValues;
|
||||
}
|
||||
|
||||
protected final Map<String, Object> getParameterValues() {
|
||||
return this.parameterValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* The start segment of the cypher query. START is prepended
|
||||
* to the statement provided and should <em>not</em> be
|
||||
* included.
|
||||
*
|
||||
* @param startStatement the start fragment of the cypher query.
|
||||
*/
|
||||
public void setStartStatement(String startStatement) {
|
||||
this.startStatement = startStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* The return statement of the cypher query. RETURN is prepended
|
||||
* to the statement provided and should <em>not</em> be
|
||||
* included
|
||||
*
|
||||
* @param returnStatement the return fragment of the cypher query.
|
||||
*/
|
||||
public void setReturnStatement(String returnStatement) {
|
||||
this.returnStatement = returnStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional match fragment of the cypher query. MATCH is
|
||||
* prepended to the statement provided and should <em>not</em>
|
||||
* be included.
|
||||
*
|
||||
* @param matchStatement the match fragment of the cypher query
|
||||
*/
|
||||
public void setMatchStatement(String matchStatement) {
|
||||
this.matchStatement = matchStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional where fragment of the cypher query. WHERE is
|
||||
* prepended to the statement provided and should <em>not</em>
|
||||
* be included.
|
||||
*
|
||||
* @param whereStatement where fragment of the cypher query
|
||||
*/
|
||||
public void setWhereStatement(String whereStatement) {
|
||||
this.whereStatement = whereStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of properties to order the results by. This is
|
||||
* required so that subsequent page requests pull back the
|
||||
* segment of results correctly. ORDER BY is prepended to
|
||||
* the statement provided and should <em>not</em> be included.
|
||||
*
|
||||
* @param orderByStatement order by fragment of the cypher query.
|
||||
*/
|
||||
public void setOrderByStatement(String orderByStatement) {
|
||||
this.orderByStatement = orderByStatement;
|
||||
}
|
||||
|
||||
protected SessionFactory getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the session factory for the reader.
|
||||
* @param sessionFactory the factory to use for the reader.
|
||||
*/
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object type to be returned from each call to {@link #read()}
|
||||
*
|
||||
* @param targetType the type of object to return.
|
||||
*/
|
||||
public void setTargetType(Class<T> targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
protected final Class<T> getTargetType() {
|
||||
return this.targetType;
|
||||
}
|
||||
|
||||
protected String generateLimitCypherQuery() {
|
||||
StringBuilder query = new StringBuilder(128);
|
||||
|
||||
query.append("START ").append(startStatement);
|
||||
query.append(matchStatement != null ? " MATCH " + matchStatement : "");
|
||||
query.append(whereStatement != null ? " WHERE " + whereStatement : "");
|
||||
query.append(" RETURN ").append(returnStatement);
|
||||
query.append(" ORDER BY ").append(orderByStatement);
|
||||
query.append(" SKIP " + (pageSize * page));
|
||||
query.append(" LIMIT " + pageSize);
|
||||
|
||||
String resultingQuery = query.toString();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(resultingQuery);
|
||||
}
|
||||
|
||||
return resultingQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks mandatory properties
|
||||
*
|
||||
* @see InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(sessionFactory != null,"A SessionFactory is required");
|
||||
Assert.state(targetType != null, "The type to be returned is required");
|
||||
Assert.state(StringUtils.hasText(startStatement), "A START statement is required");
|
||||
Assert.state(StringUtils.hasText(returnStatement), "A RETURN statement is required");
|
||||
Assert.state(StringUtils.hasText(orderByStatement), "A ORDER BY statement is required");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2020 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -413,16 +413,6 @@ implements InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up resources.
|
||||
* @throws Exception If unable to clean up resources
|
||||
* @deprecated This method is deprecated in favor of
|
||||
* {@link AbstractCursorItemReader#cleanupOnClose(java.sql.Connection)} and
|
||||
* will be removed in a future release
|
||||
*/
|
||||
@Deprecated
|
||||
protected abstract void cleanupOnClose() throws Exception;
|
||||
|
||||
/**
|
||||
* Clean up resources.
|
||||
* @param connection to the database
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2017 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -43,6 +43,7 @@ import org.springframework.util.Assert;
|
||||
* @author Dave Syer
|
||||
* @author Thomas Risberg
|
||||
* @author Michael Minella
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
|
||||
@@ -129,40 +130,4 @@ public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do perform the actual write operation using {@link HibernateOperations}.
|
||||
* This can be overridden in a subclass if necessary.
|
||||
*
|
||||
* @param hibernateTemplate
|
||||
* the HibernateTemplate to use for the operation
|
||||
* @param items
|
||||
* the list of items to use for the write
|
||||
* @deprecated As of 2.2 in favor of using Hibernate's session management APIs directly
|
||||
*/
|
||||
@Deprecated
|
||||
protected void doWrite(HibernateOperations hibernateTemplate,
|
||||
List<? extends T> items) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Writing to Hibernate with " + items.size()
|
||||
+ " items.");
|
||||
}
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
long saveOrUpdateCount = 0;
|
||||
for (T item : items) {
|
||||
if (!hibernateTemplate.contains(item)) {
|
||||
hibernateTemplate.saveOrUpdate(item);
|
||||
saveOrUpdateCount++;
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(saveOrUpdateCount + " entities saved/updated.");
|
||||
logger.debug((items.size() - saveOrUpdateCount)
|
||||
+ " entities found in session.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2020 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -142,18 +142,6 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
|
||||
return rowMapper.mapRow(rs, currentRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the cursor and database connection.
|
||||
* @deprecated This method is deprecated in favor of
|
||||
* {@link JdbcCursorItemReader#cleanupOnClose(java.sql.Connection)} and will
|
||||
* be removed in a future release
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
protected void cleanupOnClose() throws Exception {
|
||||
JdbcUtils.closeStatement(this.preparedStatement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the cursor and database connection.
|
||||
* @param connection to the database
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2020 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -238,18 +238,6 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
|
||||
return rowMapper.mapRow(rs, currentRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the cursor and database connection.
|
||||
* @deprecated This method is deprecated in favor of
|
||||
* {@link StoredProcedureItemReader#cleanupOnClose(java.sql.Connection)} and
|
||||
* will be removed in a future release
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
protected void cleanupOnClose() throws Exception {
|
||||
JdbcUtils.closeStatement(this.callableStatement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the cursor and database connection.
|
||||
* @param connection to the database
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2018 the original author or authors.
|
||||
* Copyright 2017-2021 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.
|
||||
@@ -217,22 +217,6 @@ public class HibernatePagingItemReaderBuilder<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicator for whether to use a {@link org.hibernate.StatelessSession}
|
||||
* (<code>true</code>) or a {@link org.hibernate.Session} (<code>false</code>).
|
||||
*
|
||||
* @param useStatelessSession Defaults to false
|
||||
* @return this instance for method chaining
|
||||
* @see HibernatePagingItemReader#setUseStatelessSession(boolean)
|
||||
* @deprecated This method is deprecated in favor of
|
||||
* {@link HibernatePagingItemReaderBuilder#useStatelessSession} and will be
|
||||
* removed in a future version.
|
||||
*/
|
||||
@Deprecated
|
||||
public HibernatePagingItemReaderBuilder<T> useSatelessSession(boolean useStatelessSession) {
|
||||
return useStatelessSession(useStatelessSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicator for whether to use a {@link org.hibernate.StatelessSession}
|
||||
* (<code>true</code>) or a {@link org.hibernate.Session} (<code>false</code>).
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2019 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
|
||||
*
|
||||
* https://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.item.database.support;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.item.database.JdbcCursorItemReader;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.SqlTypeValue;
|
||||
import org.springframework.jdbc.core.StatementCreatorUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link PreparedStatementSetter} interface that accepts
|
||||
* a list of values to be set on a PreparedStatement. This is usually used in
|
||||
* conjunction with the {@link JdbcCursorItemReader} to allow for the replacement
|
||||
* of bind variables when generating the cursor. The order of the list will be
|
||||
* used to determine the ordering of setting variables. For example, the first
|
||||
* item in the list will be the first bind variable set. (i.e. it will
|
||||
* correspond to the first '?' in the SQL statement)
|
||||
*
|
||||
* @deprecated use {@link org.springframework.jdbc.core.ArgumentPreparedStatementSetter}
|
||||
* instead.
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class ListPreparedStatementSetter implements
|
||||
PreparedStatementSetter, InitializingBean {
|
||||
|
||||
private List<?> parameters;
|
||||
|
||||
public ListPreparedStatementSetter() {}
|
||||
|
||||
public ListPreparedStatementSetter(List<?> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
StatementCreatorUtils.setParameterValue(ps, i + 1, SqlTypeValue.TYPE_UNKNOWN, parameters.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameter values that will be set on the PreparedStatement.
|
||||
* It is assumed that their order in the List is the order of the parameters
|
||||
* in the PreparedStatement.
|
||||
*
|
||||
* @param parameters list containing the parameter values to be used.
|
||||
* @deprecated In favor of the constructor
|
||||
*/
|
||||
@Deprecated
|
||||
public void setParameters(List<?> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(parameters, "Parameters must be provided");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2020 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -142,7 +142,7 @@ public class MultiResourceItemReader<T> extends AbstractItemStreamItemReader<T>
|
||||
private T readFromDelegate() throws Exception {
|
||||
T item = delegate.read();
|
||||
if(item instanceof ResourceAware){
|
||||
((ResourceAware) item).setResource(getCurrentResource());
|
||||
((ResourceAware) item).setResource(resources[currentResource]);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
@@ -247,20 +247,4 @@ public class MultiResourceItemReader<T> extends AbstractItemStreamItemReader<T>
|
||||
this.resources = Arrays.asList(resources).toArray(new Resource[resources.length]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the current resource.
|
||||
* @return the current resource or {@code null} if all resources have been
|
||||
* processed or the first resource has not been assigned yet.
|
||||
*
|
||||
* @deprecated In favor of using {@link ResourceAware} instead.
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public Resource getCurrentResource() {
|
||||
if (currentResource >= resources.length || currentResource < 0) {
|
||||
return null;
|
||||
}
|
||||
return resources[currentResource];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2020 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
|
||||
*
|
||||
* https://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.item.file.transform;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
* @deprecated Use {@link FormatterLineAggregator#setFormat(java.lang.String)}
|
||||
* for alignment (See examples in {@code FormatterLineAggregatorTests})
|
||||
*/
|
||||
@Deprecated
|
||||
public enum Alignment {
|
||||
CENTER("CENTER", "center"),
|
||||
RIGHT("RIGHT", "right"),
|
||||
LEFT("LEFT", "left");
|
||||
|
||||
private String code;
|
||||
private String label;
|
||||
|
||||
private Alignment(String code, String label) {
|
||||
Assert.notNull(code, "'code' must not be null");
|
||||
|
||||
this.code = code;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public Comparable<String> getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getStringCode() {
|
||||
return (String) getCode();
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
if (this.label != null) {
|
||||
return label;
|
||||
}
|
||||
|
||||
return getCode().toString();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.util.Assert;
|
||||
* Utility methods for files used in batch processing.
|
||||
*
|
||||
* @author Peter Zozom
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
public final class FileUtils {
|
||||
|
||||
@@ -89,28 +90,6 @@ public final class FileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up output file for batch processing. This method implements common logic for handling output files when
|
||||
* starting or restarting file I/O. When starting output file processing, creates/overwrites new file. When
|
||||
* restarting output file processing, checks whether file is writable.
|
||||
*
|
||||
* @param file file to be set up
|
||||
* @param restarted true signals that we are restarting output file processing
|
||||
* @param overwriteOutputFile If set to true, output file will be overwritten (this flag is ignored when processing
|
||||
* is restart)
|
||||
*
|
||||
* @throws IllegalArgumentException when file is null
|
||||
* @throws ItemStreamException when starting output file processing, file exists and flag "overwriteOutputFile" is
|
||||
* set to false
|
||||
* @throws ItemStreamException when unable to create file or file is not writable
|
||||
*
|
||||
* @deprecated use the version with explicit append parameter instead. Here append=false is assumed.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setUpOutputFile(File file, boolean restarted, boolean overwriteOutputFile) {
|
||||
setUpOutputFile(file, restarted, false, overwriteOutputFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file if it doesn't already exist.
|
||||
*
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2020 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
|
||||
*
|
||||
* https://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.item.xml;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLEventWriter;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stax.StAXResult;
|
||||
import javax.xml.transform.stax.StAXSource;
|
||||
|
||||
|
||||
/**
|
||||
* StAX utility methods.
|
||||
* <br>
|
||||
* This class is thread-safe.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
* @deprecated in favor of {@link org.springframework.util.xml.StaxUtils}
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class StaxUtils {
|
||||
|
||||
public static Source getSource(XMLEventReader r) throws XMLStreamException {
|
||||
return new StAXSource(r);
|
||||
}
|
||||
|
||||
public static Result getResult(XMLEventWriter w) {
|
||||
return new StAXResult(w);
|
||||
}
|
||||
|
||||
public static XMLInputFactory createXmlInputFactory() {
|
||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||
xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
|
||||
xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
|
||||
return xmlInputFactory;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2013 the original author or authors.
|
||||
* Copyright 2006-2021 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.
|
||||
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.when;
|
||||
* @author Thomas Risberg
|
||||
* @author Michael Minella
|
||||
* @author Will Schipp
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
public class HibernateItemWriterTests {
|
||||
|
||||
@@ -83,7 +84,6 @@ public class HibernateItemWriterTests {
|
||||
writer.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testWriteAndFlushSunnyDayHibernate3() throws Exception {
|
||||
this.writer.setSessionFactory(this.factory);
|
||||
@@ -98,7 +98,6 @@ public class HibernateItemWriterTests {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testWriteAndFlushWithFailureHibernate3() throws Exception {
|
||||
this.writer.setSessionFactory(this.factory);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2019 the original author or authors.
|
||||
* Copyright 2008-2021 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.
|
||||
@@ -102,33 +102,6 @@ public class MultiResourceItemReaderIntegrationTests {
|
||||
tested.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCurrentResource() throws Exception {
|
||||
|
||||
tested.open(ctx);
|
||||
|
||||
assertEquals("1", tested.read());
|
||||
assertSame(r1, tested.getCurrentResource());
|
||||
assertEquals("2", tested.read());
|
||||
assertSame(r1, tested.getCurrentResource());
|
||||
assertEquals("3", tested.read());
|
||||
assertSame(r1, tested.getCurrentResource());
|
||||
assertEquals("4", tested.read());
|
||||
assertSame(r2, tested.getCurrentResource());
|
||||
assertEquals("5", tested.read());
|
||||
assertSame(r2, tested.getCurrentResource());
|
||||
assertEquals("6", tested.read());
|
||||
assertSame(r4, tested.getCurrentResource());
|
||||
assertEquals("7", tested.read());
|
||||
assertSame(r5, tested.getCurrentResource());
|
||||
assertEquals("8", tested.read());
|
||||
assertSame(r5, tested.getCurrentResource());
|
||||
assertEquals(null, tested.read());
|
||||
assertSame(null, tested.getCurrentResource());
|
||||
|
||||
tested.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestartWhenStateNotSaved() throws Exception {
|
||||
|
||||
@@ -433,13 +406,6 @@ public class MultiResourceItemReaderIntegrationTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCurrentResourceBeforeRead() throws Exception {
|
||||
tested.open(ctx);
|
||||
assertNull("There is no 'current' resource before read is called", tested.getCurrentResource());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* No resources to read should result in error in strict mode.
|
||||
*/
|
||||
|
||||
@@ -1,423 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.integration.chunk;
|
||||
|
||||
import org.springframework.batch.core.ChunkListener;
|
||||
import org.springframework.batch.core.ItemReadListener;
|
||||
import org.springframework.batch.core.ItemWriteListener;
|
||||
import org.springframework.batch.core.SkipListener;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.builder.FaultTolerantStepBuilder;
|
||||
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.batch.core.step.item.KeyGenerator;
|
||||
import org.springframework.batch.core.step.skip.SkipPolicy;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.repeat.CompletionPolicy;
|
||||
import org.springframework.batch.repeat.RepeatOperations;
|
||||
import org.springframework.batch.repeat.exception.ExceptionHandler;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.retry.RetryPolicy;
|
||||
import org.springframework.retry.backoff.BackOffPolicy;
|
||||
import org.springframework.retry.policy.RetryContextCache;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Builder for a master step in a remote chunking setup. This builder creates and
|
||||
* sets a {@link ChunkMessageChannelItemWriter} on the master step.
|
||||
*
|
||||
* <p>If no {@code messagingTemplate} is provided through
|
||||
* {@link RemoteChunkingMasterStepBuilder#messagingTemplate(MessagingTemplate)},
|
||||
* this builder will create one and set its default channel to the {@code outputChannel}
|
||||
* provided through {@link RemoteChunkingMasterStepBuilder#outputChannel(MessageChannel)}.</p>
|
||||
*
|
||||
* <p>If a {@code messagingTemplate} is provided, it is assumed that it is fully configured
|
||||
* and that its default channel is set to an output channel on which requests to workers
|
||||
* will be sent.</p>
|
||||
*
|
||||
* @param <I> type of input items
|
||||
* @param <O> type of output items
|
||||
*
|
||||
* @deprecated Use {@link RemoteChunkingManagerStepBuilder} instead.
|
||||
*
|
||||
* @since 4.1
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
@Deprecated
|
||||
public class RemoteChunkingMasterStepBuilder<I, O> extends FaultTolerantStepBuilder<I, O> {
|
||||
|
||||
private MessagingTemplate messagingTemplate;
|
||||
private PollableChannel inputChannel;
|
||||
private MessageChannel outputChannel;
|
||||
|
||||
private final int DEFAULT_MAX_WAIT_TIMEOUTS = 40;
|
||||
private static final long DEFAULT_THROTTLE_LIMIT = 6;
|
||||
private int maxWaitTimeouts = DEFAULT_MAX_WAIT_TIMEOUTS;
|
||||
private long throttleLimit = DEFAULT_THROTTLE_LIMIT;
|
||||
|
||||
/**
|
||||
* Create a new {@link RemoteChunkingMasterStepBuilder}.
|
||||
*
|
||||
* @param stepName name of the master step
|
||||
*/
|
||||
public RemoteChunkingMasterStepBuilder(String stepName) {
|
||||
super(new StepBuilder(stepName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the input channel on which replies from workers will be received.
|
||||
* The provided input channel will be set as a reply channel on the
|
||||
* {@link ChunkMessageChannelItemWriter} created by this builder.
|
||||
*
|
||||
* @param inputChannel the input channel
|
||||
* @return this builder instance for fluent chaining
|
||||
*
|
||||
* @see ChunkMessageChannelItemWriter#setReplyChannel
|
||||
*/
|
||||
public RemoteChunkingMasterStepBuilder<I, O> inputChannel(PollableChannel inputChannel) {
|
||||
Assert.notNull(inputChannel, "inputChannel must not be null");
|
||||
this.inputChannel = inputChannel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output channel on which requests to workers will be sent. By using
|
||||
* this setter, a default messaging template will be created and the output
|
||||
* channel will be set as its default channel.
|
||||
* <p>Use either this setter or {@link RemoteChunkingMasterStepBuilder#messagingTemplate(MessagingTemplate)}
|
||||
* to provide a fully configured messaging template.</p>
|
||||
*
|
||||
* @param outputChannel the output channel.
|
||||
* @return this builder instance for fluent chaining
|
||||
*
|
||||
* @see RemoteChunkingMasterStepBuilder#messagingTemplate(MessagingTemplate)
|
||||
*/
|
||||
public RemoteChunkingMasterStepBuilder<I, O> outputChannel(MessageChannel outputChannel) {
|
||||
Assert.notNull(outputChannel, "outputChannel must not be null");
|
||||
this.outputChannel = outputChannel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link MessagingTemplate} to use to send data to workers.
|
||||
* <strong>The default channel of the messaging template must be set</strong>.
|
||||
* <p>Use either this setter to provide a fully configured messaging template or
|
||||
* provide an output channel through {@link RemoteChunkingMasterStepBuilder#outputChannel(MessageChannel)}
|
||||
* and a default messaging template will be created.</p>
|
||||
*
|
||||
* @param messagingTemplate the messaging template to use
|
||||
* @return this builder instance for fluent chaining
|
||||
* @see RemoteChunkingMasterStepBuilder#outputChannel(MessageChannel)
|
||||
*/
|
||||
public RemoteChunkingMasterStepBuilder<I, O> messagingTemplate(MessagingTemplate messagingTemplate) {
|
||||
Assert.notNull(messagingTemplate, "messagingTemplate must not be null");
|
||||
this.messagingTemplate = messagingTemplate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum number of times to wait at the end of a step for a non-null result from the remote workers. This is a
|
||||
* multiplier on the receive timeout set separately on the gateway. The ideal value is a compromise between allowing
|
||||
* slow workers time to finish, and responsiveness if there is a dead worker. Defaults to 40.
|
||||
*
|
||||
* @param maxWaitTimeouts the maximum number of wait timeouts
|
||||
* @return this builder instance for fluent chaining
|
||||
* @see ChunkMessageChannelItemWriter#setMaxWaitTimeouts(int)
|
||||
*/
|
||||
public RemoteChunkingMasterStepBuilder<I, O> maxWaitTimeouts(int maxWaitTimeouts) {
|
||||
Assert.isTrue(maxWaitTimeouts > 0, "maxWaitTimeouts must be greater than zero");
|
||||
this.maxWaitTimeouts = maxWaitTimeouts;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the throttle limit. This limits the number of pending requests for chunk processing to avoid
|
||||
* overwhelming the receivers.
|
||||
*
|
||||
* @param throttleLimit the throttle limit to set
|
||||
* @return this builder instance for fluent chaining
|
||||
* @see ChunkMessageChannelItemWriter#setThrottleLimit(long)
|
||||
*/
|
||||
public RemoteChunkingMasterStepBuilder<I, O> throttleLimit(long throttleLimit) {
|
||||
Assert.isTrue(throttleLimit > 0, "throttleLimit must be greater than zero");
|
||||
this.throttleLimit = throttleLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a master {@link TaskletStep}.
|
||||
*
|
||||
* @return the configured master step
|
||||
* @see RemoteChunkHandlerFactoryBean
|
||||
*/
|
||||
public TaskletStep build() {
|
||||
Assert.notNull(this.inputChannel, "An InputChannel must be provided");
|
||||
Assert.state(this.outputChannel == null || this.messagingTemplate == null,
|
||||
"You must specify either an outputChannel or a messagingTemplate but not both.");
|
||||
|
||||
// configure messaging template
|
||||
if (this.messagingTemplate == null) {
|
||||
this.messagingTemplate = new MessagingTemplate();
|
||||
this.messagingTemplate.setDefaultChannel(this.outputChannel);
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("No messagingTemplate was provided, using a default one");
|
||||
}
|
||||
}
|
||||
|
||||
// configure item writer
|
||||
ChunkMessageChannelItemWriter<O> chunkMessageChannelItemWriter = new ChunkMessageChannelItemWriter<>();
|
||||
chunkMessageChannelItemWriter.setMessagingOperations(this.messagingTemplate);
|
||||
chunkMessageChannelItemWriter.setMaxWaitTimeouts(this.maxWaitTimeouts);
|
||||
chunkMessageChannelItemWriter.setThrottleLimit(this.throttleLimit);
|
||||
chunkMessageChannelItemWriter.setReplyChannel(this.inputChannel);
|
||||
super.writer(chunkMessageChannelItemWriter);
|
||||
|
||||
return super.build();
|
||||
}
|
||||
|
||||
/*
|
||||
* The following methods override those from parent builders and return
|
||||
* the current builder type.
|
||||
* FIXME: Change parent builders to be generic and return current builder
|
||||
* type in each method.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> reader(ItemReader<? extends I> reader) {
|
||||
super.reader(reader);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> repository(JobRepository jobRepository) {
|
||||
super.repository(jobRepository);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> transactionManager(PlatformTransactionManager transactionManager) {
|
||||
super.transactionManager(transactionManager);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> listener(Object listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> listener(SkipListener<? super I, ? super O> listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> listener(ChunkListener listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> transactionAttribute(TransactionAttribute transactionAttribute) {
|
||||
super.transactionAttribute(transactionAttribute);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> listener(org.springframework.retry.RetryListener listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> keyGenerator(KeyGenerator keyGenerator) {
|
||||
super.keyGenerator(keyGenerator);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> retryLimit(int retryLimit) {
|
||||
super.retryLimit(retryLimit);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> retryPolicy(RetryPolicy retryPolicy) {
|
||||
super.retryPolicy(retryPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> backOffPolicy(BackOffPolicy backOffPolicy) {
|
||||
super.backOffPolicy(backOffPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> retryContextCache(RetryContextCache retryContextCache) {
|
||||
super.retryContextCache(retryContextCache);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> skipLimit(int skipLimit) {
|
||||
super.skipLimit(skipLimit);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> noSkip(Class<? extends Throwable> type) {
|
||||
super.noSkip(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> skip(Class<? extends Throwable> type) {
|
||||
super.skip(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> skipPolicy(SkipPolicy skipPolicy) {
|
||||
super.skipPolicy(skipPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> noRollback(Class<? extends Throwable> type) {
|
||||
super.noRollback(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> noRetry(Class<? extends Throwable> type) {
|
||||
super.noRetry(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> retry(Class<? extends Throwable> type) {
|
||||
super.retry(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> stream(ItemStream stream) {
|
||||
super.stream(stream);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> chunk(int chunkSize) {
|
||||
super.chunk(chunkSize);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> chunk(CompletionPolicy completionPolicy) {
|
||||
super.chunk(completionPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will throw a {@link UnsupportedOperationException} since
|
||||
* the item writer of the master step in a remote chunking setup will be
|
||||
* automatically set to an instance of {@link ChunkMessageChannelItemWriter}.
|
||||
*
|
||||
* When building a master step for remote chunking, no item writer must be
|
||||
* provided.
|
||||
*
|
||||
* @throws UnsupportedOperationException if an item writer is provided
|
||||
* @see ChunkMessageChannelItemWriter
|
||||
* @see RemoteChunkHandlerFactoryBean#setChunkWriter(ItemWriter)
|
||||
*/
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> writer(ItemWriter<? super O> writer) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("When configuring a master step " +
|
||||
"for remote chunking, the item writer will be automatically set " +
|
||||
"to an instance of ChunkMessageChannelItemWriter. The item writer " +
|
||||
"must not be provided in this case.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> readerIsTransactionalQueue() {
|
||||
super.readerIsTransactionalQueue();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> listener(ItemReadListener<? super I> listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> listener(ItemWriteListener<? super O> listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> chunkOperations(RepeatOperations repeatTemplate) {
|
||||
super.chunkOperations(repeatTemplate);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> exceptionHandler(ExceptionHandler exceptionHandler) {
|
||||
super.exceptionHandler(exceptionHandler);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> stepOperations(RepeatOperations repeatTemplate) {
|
||||
super.stepOperations(repeatTemplate);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> startLimit(int startLimit) {
|
||||
super.startLimit(startLimit);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> listener(StepExecutionListener listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> allowStartIfComplete(boolean allowStartIfComplete) {
|
||||
super.allowStartIfComplete(allowStartIfComplete);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> processor(ItemProcessor<? super I, ? extends O> itemProcessor) {
|
||||
super.processor(itemProcessor);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.integration.chunk;
|
||||
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Convenient factory for a {@link RemoteChunkingMasterStepBuilder} which sets
|
||||
* the {@link JobRepository} and {@link PlatformTransactionManager} automatically.
|
||||
*
|
||||
* @deprecated Use {@link RemoteChunkingManagerStepBuilderFactory} instead.
|
||||
*
|
||||
* @since 4.1
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
@Deprecated
|
||||
public class RemoteChunkingMasterStepBuilderFactory {
|
||||
|
||||
private JobRepository jobRepository;
|
||||
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
/**
|
||||
* Create a new {@link RemoteChunkingMasterStepBuilderFactory}.
|
||||
*
|
||||
* @param jobRepository the job repository to use
|
||||
* @param transactionManager the transaction manager to use
|
||||
*/
|
||||
public RemoteChunkingMasterStepBuilderFactory(
|
||||
JobRepository jobRepository,
|
||||
PlatformTransactionManager transactionManager) {
|
||||
|
||||
this.jobRepository = jobRepository;
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link RemoteChunkingMasterStepBuilder} and initializes its job
|
||||
* repository and transaction manager.
|
||||
*
|
||||
* @param name the name of the step
|
||||
* @param <I> type of input items
|
||||
* @param <O> type of output items
|
||||
* @return a {@link RemoteChunkingMasterStepBuilder}
|
||||
*/
|
||||
public <I, O> RemoteChunkingMasterStepBuilder<I, O> get(String name) {
|
||||
return new RemoteChunkingMasterStepBuilder<I, O>(name)
|
||||
.repository(this.jobRepository)
|
||||
.transactionManager(this.transactionManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2021 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.
|
||||
@@ -17,10 +17,8 @@ package org.springframework.batch.integration.config.annotation;
|
||||
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.integration.chunk.RemoteChunkingMasterStepBuilderFactory;
|
||||
import org.springframework.batch.integration.chunk.RemoteChunkingManagerStepBuilderFactory;
|
||||
import org.springframework.batch.integration.chunk.RemoteChunkingWorkerBuilder;
|
||||
import org.springframework.batch.integration.partition.RemotePartitioningMasterStepBuilderFactory;
|
||||
import org.springframework.batch.integration.partition.RemotePartitioningManagerStepBuilderFactory;
|
||||
import org.springframework.batch.integration.partition.RemotePartitioningWorkerStepBuilderFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -44,14 +42,10 @@ public class BatchIntegrationConfiguration implements InitializingBean {
|
||||
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
private RemoteChunkingMasterStepBuilderFactory remoteChunkingMasterStepBuilderFactory;
|
||||
|
||||
private RemoteChunkingManagerStepBuilderFactory remoteChunkingManagerStepBuilderFactory;
|
||||
|
||||
private RemoteChunkingWorkerBuilder remoteChunkingWorkerBuilder;
|
||||
|
||||
private RemotePartitioningMasterStepBuilderFactory remotePartitioningMasterStepBuilderFactory;
|
||||
|
||||
private RemotePartitioningManagerStepBuilderFactory remotePartitioningManagerStepBuilderFactory;
|
||||
|
||||
private RemotePartitioningWorkerStepBuilderFactory remotePartitioningWorkerStepBuilderFactory;
|
||||
@@ -67,12 +61,6 @@ public class BatchIntegrationConfiguration implements InitializingBean {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Bean
|
||||
public RemoteChunkingMasterStepBuilderFactory remoteChunkingMasterStepBuilderFactory() {
|
||||
return this.remoteChunkingMasterStepBuilderFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RemoteChunkingManagerStepBuilderFactory remoteChunkingManagerStepBuilderFactory() {
|
||||
return this.remoteChunkingManagerStepBuilderFactory;
|
||||
@@ -83,12 +71,6 @@ public class BatchIntegrationConfiguration implements InitializingBean {
|
||||
return remoteChunkingWorkerBuilder;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Bean
|
||||
public RemotePartitioningMasterStepBuilderFactory remotePartitioningMasterStepBuilderFactory() {
|
||||
return remotePartitioningMasterStepBuilderFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RemotePartitioningManagerStepBuilderFactory remotePartitioningManagerStepBuilderFactory() {
|
||||
return this.remotePartitioningManagerStepBuilderFactory;
|
||||
@@ -101,13 +83,9 @@ public class BatchIntegrationConfiguration implements InitializingBean {
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.remoteChunkingMasterStepBuilderFactory = new RemoteChunkingMasterStepBuilderFactory(this.jobRepository,
|
||||
this.transactionManager);
|
||||
this.remoteChunkingManagerStepBuilderFactory = new RemoteChunkingManagerStepBuilderFactory(this.jobRepository,
|
||||
this.transactionManager);
|
||||
this.remoteChunkingWorkerBuilder = new RemoteChunkingWorkerBuilder<>();
|
||||
this.remotePartitioningMasterStepBuilderFactory = new RemotePartitioningMasterStepBuilderFactory(this.jobRepository,
|
||||
this.jobExplorer, this.transactionManager);
|
||||
this.remotePartitioningManagerStepBuilderFactory = new RemotePartitioningManagerStepBuilderFactory(this.jobRepository,
|
||||
this.jobExplorer, this.transactionManager);
|
||||
this.remotePartitioningWorkerStepBuilderFactory = new RemotePartitioningWorkerStepBuilderFactory(this.jobRepository,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -35,9 +35,5 @@ public class BatchIntegrationNamespaceHandler extends AbstractIntegrationNamespa
|
||||
this.registerBeanDefinitionParser("remote-chunking-manager", remoteChunkingManagerParser);
|
||||
RemoteChunkingWorkerParser remoteChunkingWorkerParser = new RemoteChunkingWorkerParser();
|
||||
this.registerBeanDefinitionParser("remote-chunking-worker", remoteChunkingWorkerParser);
|
||||
|
||||
// TODO remove the following when related deprecated APIs are removed
|
||||
this.registerBeanDefinitionParser("remote-chunking-master", remoteChunkingManagerParser);
|
||||
this.registerBeanDefinitionParser("remote-chunking-slave", remoteChunkingWorkerParser);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.integration.partition;
|
||||
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.partition.PartitionHandler;
|
||||
import org.springframework.batch.core.partition.StepExecutionSplitter;
|
||||
import org.springframework.batch.core.partition.support.Partitioner;
|
||||
import org.springframework.batch.core.partition.support.StepExecutionAggregator;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.builder.PartitionStepBuilder;
|
||||
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.dsl.IntegrationFlows;
|
||||
import org.springframework.integration.dsl.StandardIntegrationFlow;
|
||||
import org.springframework.integration.dsl.context.IntegrationFlowContext;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Builder for a master step in a remote partitioning setup. This builder creates and
|
||||
* sets a {@link MessageChannelPartitionHandler} on the master step.
|
||||
*
|
||||
* <p>If no {@code messagingTemplate} is provided through
|
||||
* {@link RemotePartitioningMasterStepBuilder#messagingTemplate(MessagingTemplate)},
|
||||
* this builder will create one and set its default channel to the {@code outputChannel}
|
||||
* provided through {@link RemotePartitioningMasterStepBuilder#outputChannel(MessageChannel)}.</p>
|
||||
*
|
||||
* <p>If a {@code messagingTemplate} is provided, it is assumed that it is fully configured
|
||||
* and that its default channel is set to an output channel on which requests to workers
|
||||
* will be sent.</p>
|
||||
*
|
||||
* @deprecated Use {@link RemotePartitioningManagerStepBuilder} instead.
|
||||
*
|
||||
* @since 4.1
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
@Deprecated
|
||||
public class RemotePartitioningMasterStepBuilder extends PartitionStepBuilder {
|
||||
|
||||
private static final long DEFAULT_POLL_INTERVAL = 10000L;
|
||||
private static final long DEFAULT_TIMEOUT = -1L;
|
||||
|
||||
private MessagingTemplate messagingTemplate;
|
||||
private MessageChannel inputChannel;
|
||||
private MessageChannel outputChannel;
|
||||
private JobExplorer jobExplorer;
|
||||
private BeanFactory beanFactory;
|
||||
private long pollInterval = DEFAULT_POLL_INTERVAL;
|
||||
private long timeout = DEFAULT_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Create a new {@link RemotePartitioningMasterStepBuilder}.
|
||||
* @param stepName name of the master step
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder(String stepName) {
|
||||
super(new StepBuilder(stepName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the input channel on which replies from workers will be received.
|
||||
* @param inputChannel the input channel
|
||||
* @return this builder instance for fluent chaining
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder inputChannel(MessageChannel inputChannel) {
|
||||
Assert.notNull(inputChannel, "inputChannel must not be null");
|
||||
this.inputChannel = inputChannel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output channel on which requests to workers will be sent. By using
|
||||
* this setter, a default messaging template will be created and the output
|
||||
* channel will be set as its default channel.
|
||||
* <p>Use either this setter or {@link RemotePartitioningMasterStepBuilder#messagingTemplate(MessagingTemplate)}
|
||||
* to provide a fully configured messaging template.</p>
|
||||
*
|
||||
* @param outputChannel the output channel.
|
||||
* @return this builder instance for fluent chaining
|
||||
* @see RemotePartitioningMasterStepBuilder#messagingTemplate(MessagingTemplate)
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder outputChannel(MessageChannel outputChannel) {
|
||||
Assert.notNull(outputChannel, "outputChannel must not be null");
|
||||
this.outputChannel = outputChannel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link MessagingTemplate} to use to send data to workers.
|
||||
* <strong>The default channel of the messaging template must be set</strong>.
|
||||
* <p>Use either this setter to provide a fully configured messaging template or
|
||||
* provide an output channel through {@link RemotePartitioningMasterStepBuilder#outputChannel(MessageChannel)}
|
||||
* and a default messaging template will be created.</p>
|
||||
*
|
||||
* @param messagingTemplate the messaging template to use
|
||||
* @return this builder instance for fluent chaining
|
||||
* @see RemotePartitioningMasterStepBuilder#outputChannel(MessageChannel)
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder messagingTemplate(MessagingTemplate messagingTemplate) {
|
||||
Assert.notNull(messagingTemplate, "messagingTemplate must not be null");
|
||||
this.messagingTemplate = messagingTemplate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the job explorer.
|
||||
* @param jobExplorer the job explorer to use.
|
||||
* @return this builder instance for fluent chaining
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder jobExplorer(JobExplorer jobExplorer) {
|
||||
Assert.notNull(jobExplorer, "jobExplorer must not be null");
|
||||
this.jobExplorer = jobExplorer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* How often to poll the job repository for the status of the workers. Defaults to 10 seconds.
|
||||
* @param pollInterval the poll interval value in milliseconds
|
||||
* @return this builder instance for fluent chaining
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder pollInterval(long pollInterval) {
|
||||
Assert.isTrue(pollInterval > 0, "The poll interval must be greater than zero");
|
||||
this.pollInterval = pollInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When using job repository polling, the time limit to wait. Defaults to -1 (no timeout).
|
||||
* @param timeout the timeout value in milliseconds
|
||||
* @return this builder instance for fluent chaining
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder timeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean factory.
|
||||
* @param beanFactory the bean factory to use
|
||||
* @return this builder instance for fluent chaining
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder beanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Step build() {
|
||||
Assert.state(this.outputChannel == null || this.messagingTemplate == null,
|
||||
"You must specify either an outputChannel or a messagingTemplate but not both.");
|
||||
|
||||
// configure messaging template
|
||||
if (this.messagingTemplate == null) {
|
||||
this.messagingTemplate = new MessagingTemplate();
|
||||
this.messagingTemplate.setDefaultChannel(this.outputChannel);
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("No messagingTemplate was provided, using a default one");
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the partition handler
|
||||
final MessageChannelPartitionHandler partitionHandler = new MessageChannelPartitionHandler();
|
||||
partitionHandler.setStepName(getStepName());
|
||||
partitionHandler.setGridSize(getGridSize());
|
||||
partitionHandler.setMessagingOperations(this.messagingTemplate);
|
||||
|
||||
if (isPolling()) {
|
||||
partitionHandler.setJobExplorer(this.jobExplorer);
|
||||
partitionHandler.setPollInterval(this.pollInterval);
|
||||
partitionHandler.setTimeout(this.timeout);
|
||||
}
|
||||
else {
|
||||
PollableChannel replies = new QueueChannel();
|
||||
partitionHandler.setReplyChannel(replies);
|
||||
StandardIntegrationFlow standardIntegrationFlow = IntegrationFlows
|
||||
.from(this.inputChannel)
|
||||
.aggregate(aggregatorSpec -> aggregatorSpec.processor(partitionHandler))
|
||||
.channel(replies)
|
||||
.get();
|
||||
IntegrationFlowContext integrationFlowContext = this.beanFactory.getBean(IntegrationFlowContext.class);
|
||||
integrationFlowContext.registration(standardIntegrationFlow)
|
||||
.autoStartup(false)
|
||||
.register();
|
||||
}
|
||||
|
||||
try {
|
||||
partitionHandler.afterPropertiesSet();
|
||||
super.partitionHandler(partitionHandler);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new BeanCreationException("Unable to create a master step for remote partitioning", e);
|
||||
}
|
||||
|
||||
return super.build();
|
||||
}
|
||||
|
||||
private boolean isPolling() {
|
||||
return this.inputChannel == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder repository(JobRepository jobRepository) {
|
||||
super.repository(jobRepository);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder transactionManager(PlatformTransactionManager transactionManager) {
|
||||
super.transactionManager(transactionManager);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder partitioner(String slaveStepName, Partitioner partitioner) {
|
||||
super.partitioner(slaveStepName, partitioner);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder gridSize(int gridSize) {
|
||||
super.gridSize(gridSize);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder step(Step step) {
|
||||
super.step(step);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder splitter(StepExecutionSplitter splitter) {
|
||||
super.splitter(splitter);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder aggregator(StepExecutionAggregator aggregator) {
|
||||
super.aggregator(aggregator);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder startLimit(int startLimit) {
|
||||
super.startLimit(startLimit);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder listener(Object listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder listener(StepExecutionListener listener) {
|
||||
super.listener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder allowStartIfComplete(boolean allowStartIfComplete) {
|
||||
super.allowStartIfComplete(allowStartIfComplete);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will throw a {@link UnsupportedOperationException} since
|
||||
* the partition handler of the master step will be automatically set to an
|
||||
* instance of {@link MessageChannelPartitionHandler}.
|
||||
*
|
||||
* When building a master step for remote partitioning using this builder,
|
||||
* no partition handler must be provided.
|
||||
*
|
||||
* @param partitionHandler a partition handler
|
||||
* @return this builder instance for fluent chaining
|
||||
* @throws UnsupportedOperationException if a partition handler is provided
|
||||
*/
|
||||
@Override
|
||||
public RemotePartitioningMasterStepBuilder partitionHandler(PartitionHandler partitionHandler) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("When configuring a master step " +
|
||||
"for remote partitioning using the RemotePartitioningMasterStepBuilder, " +
|
||||
"the partition handler will be automatically set to an instance " +
|
||||
"of MessageChannelPartitionHandler. The partition handler must " +
|
||||
"not be provided in this case.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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
|
||||
*
|
||||
* https://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.integration.partition;
|
||||
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Convenient factory for a {@link RemotePartitioningMasterStepBuilder} which sets
|
||||
* the {@link JobRepository}, {@link JobExplorer}, {@link BeanFactory} and
|
||||
* {@link PlatformTransactionManager} automatically.
|
||||
*
|
||||
* @deprecated Use {@link RemotePartitioningManagerStepBuilderFactory} instead
|
||||
*
|
||||
* @since 4.1
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
@Deprecated
|
||||
public class RemotePartitioningMasterStepBuilderFactory implements BeanFactoryAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
final private JobExplorer jobExplorer;
|
||||
final private JobRepository jobRepository;
|
||||
final private PlatformTransactionManager transactionManager;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link RemotePartitioningMasterStepBuilderFactory}.
|
||||
* @param jobRepository the job repository to use
|
||||
* @param jobExplorer the job explorer to use
|
||||
* @param transactionManager the transaction manager to use
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilderFactory(JobRepository jobRepository,
|
||||
JobExplorer jobExplorer, PlatformTransactionManager transactionManager) {
|
||||
|
||||
this.jobRepository = jobRepository;
|
||||
this.jobExplorer = jobExplorer;
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link RemotePartitioningMasterStepBuilder} and initializes its job
|
||||
* repository, job explorer, bean factory and transaction manager.
|
||||
* @param name the name of the step
|
||||
* @return a {@link RemotePartitioningMasterStepBuilder}
|
||||
*/
|
||||
public RemotePartitioningMasterStepBuilder get(String name) {
|
||||
return new RemotePartitioningMasterStepBuilder(name)
|
||||
.repository(this.jobRepository)
|
||||
.jobExplorer(this.jobExplorer)
|
||||
.beanFactory(this.beanFactory)
|
||||
.transactionManager(this.transactionManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2021 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.
|
||||
@@ -54,227 +54,6 @@ import static org.junit.Assert.fail;
|
||||
@SuppressWarnings("unchecked")
|
||||
public class RemoteChunkingParserTests {
|
||||
|
||||
/* TODO delete the following deprecated tests when related APIs are removed
|
||||
* /!\ Deliberately not using parametrized tests as it will be easier to delete
|
||||
* the following tests afterwards
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testRemoteChunkingSlaveParserWithProcessorDefined() {
|
||||
ApplicationContext applicationContext =
|
||||
new ClassPathXmlApplicationContext("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserTests.xml");
|
||||
|
||||
ChunkHandler chunkHandler = applicationContext.getBean(ChunkProcessorChunkHandler.class);
|
||||
ChunkProcessor chunkProcessor = (SimpleChunkProcessor) TestUtils.getPropertyValue(chunkHandler, "chunkProcessor");
|
||||
assertNotNull("ChunkProcessor must not be null", chunkProcessor);
|
||||
|
||||
ItemWriter<String> itemWriter = (ItemWriter<String>) TestUtils.getPropertyValue(chunkProcessor, "itemWriter");
|
||||
assertNotNull("ChunkProcessor ItemWriter must not be null", itemWriter);
|
||||
assertTrue("Got wrong instance of ItemWriter", itemWriter instanceof Writer);
|
||||
|
||||
ItemProcessor<String, String> itemProcessor = (ItemProcessor<String, String>) TestUtils.getPropertyValue(chunkProcessor, "itemProcessor");
|
||||
assertNotNull("ChunkProcessor ItemWriter must not be null", itemProcessor);
|
||||
assertTrue("Got wrong instance of ItemProcessor", itemProcessor instanceof Processor);
|
||||
|
||||
FactoryBean serviceActivatorFactoryBean = applicationContext.getBean(ServiceActivatorFactoryBean.class);
|
||||
assertNotNull("ServiceActivatorFactoryBean must not be null", serviceActivatorFactoryBean);
|
||||
assertNotNull("Output channel name must not be null", TestUtils.getPropertyValue(serviceActivatorFactoryBean, "outputChannelName"));
|
||||
|
||||
MessageChannel inputChannel = applicationContext.getBean("requests", MessageChannel.class);
|
||||
assertNotNull("Input channel must not be null", inputChannel);
|
||||
|
||||
String targetMethodName = (String) TestUtils.getPropertyValue(serviceActivatorFactoryBean, "targetMethodName");
|
||||
assertNotNull("Target method name must not be null", targetMethodName);
|
||||
assertTrue("Target method name must be handleChunk, got: " + targetMethodName, "handleChunk".equals(targetMethodName));
|
||||
|
||||
ChunkHandler targetObject = (ChunkHandler) TestUtils.getPropertyValue(serviceActivatorFactoryBean, "targetObject");
|
||||
assertNotNull("Target object must not be null", targetObject);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testRemoteChunkingSlaveParserWithProcessorNotDefined() {
|
||||
ApplicationContext applicationContext =
|
||||
new ClassPathXmlApplicationContext("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserNoProcessorTests.xml");
|
||||
|
||||
ChunkHandler chunkHandler = applicationContext.getBean(ChunkProcessorChunkHandler.class);
|
||||
ChunkProcessor chunkProcessor = (SimpleChunkProcessor) TestUtils.getPropertyValue(chunkHandler, "chunkProcessor");
|
||||
assertNotNull("ChunkProcessor must not be null", chunkProcessor);
|
||||
|
||||
ItemProcessor<String, String> itemProcessor = (ItemProcessor<String, String>) TestUtils.getPropertyValue(chunkProcessor, "itemProcessor");
|
||||
assertNotNull("ChunkProcessor ItemWriter must not be null", itemProcessor);
|
||||
assertTrue("Got wrong instance of ItemProcessor", itemProcessor instanceof PassThroughItemProcessor);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testRemoteChunkingMasterParser() {
|
||||
ApplicationContext applicationContext =
|
||||
new ClassPathXmlApplicationContext("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserTests.xml");
|
||||
|
||||
ItemWriter itemWriter = applicationContext.getBean("itemWriter", ChunkMessageChannelItemWriter.class);
|
||||
assertNotNull("Messaging template must not be null", TestUtils.getPropertyValue(itemWriter, "messagingGateway"));
|
||||
assertNotNull("Reply channel must not be null", TestUtils.getPropertyValue(itemWriter, "replyChannel"));
|
||||
|
||||
FactoryBean<ChunkHandler> remoteChunkingHandlerFactoryBean = applicationContext.getBean(RemoteChunkHandlerFactoryBean.class);
|
||||
assertNotNull("Chunk writer must not be null", TestUtils.getPropertyValue(remoteChunkingHandlerFactoryBean, "chunkWriter"));
|
||||
assertNotNull("Step must not be null", TestUtils.getPropertyValue(remoteChunkingHandlerFactoryBean, "step"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingMasterIdAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingIdAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The id attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The id attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingMasterMessageTemplateAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingMessageTemplateAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The message-template attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The message-template attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingMasterStepAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingStepAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The step attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The step attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingMasterReplyChannelAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingReplyChannelAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The reply-channel attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The reply-channel attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingSlaveIdAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingIdAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The id attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The id attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingSlaveInputChannelAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingInputChannelAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The input-channel attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The input-channel attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingSlaveItemWriterAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingItemWriterAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The item-writer attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The item-writer attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteChunkingSlaveOutputChannelAttrAssert() throws Exception {
|
||||
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingOutputChannelAttrTests.xml");
|
||||
|
||||
try {
|
||||
applicationContext.refresh();
|
||||
fail();
|
||||
} catch (BeanDefinitionStoreException e) {
|
||||
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
|
||||
|
||||
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
|
||||
|
||||
assertTrue("Expected: " + "The output-channel attribute must be specified" + " but got: " + iae.getMessage(),
|
||||
"The output-channel attribute must be specified".equals(iae.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO end of deprecated tests to remove */
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testRemoteChunkingWorkerParserWithProcessorDefined() {
|
||||
|
||||
@@ -55,7 +55,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
@Test
|
||||
public void inputChannelMustNotBeNull() {
|
||||
// given
|
||||
final RemotePartitioningMasterStepBuilder builder = new RemotePartitioningMasterStepBuilder("step");
|
||||
final RemotePartitioningManagerStepBuilder builder = new RemotePartitioningManagerStepBuilder("step");
|
||||
|
||||
// when
|
||||
final Exception expectedException = Assert.assertThrows(IllegalArgumentException.class,
|
||||
@@ -68,7 +68,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
@Test
|
||||
public void outputChannelMustNotBeNull() {
|
||||
// given
|
||||
final RemotePartitioningMasterStepBuilder builder = new RemotePartitioningMasterStepBuilder("step");
|
||||
final RemotePartitioningManagerStepBuilder builder = new RemotePartitioningManagerStepBuilder("step");
|
||||
|
||||
// when
|
||||
final Exception expectedException = Assert.assertThrows(IllegalArgumentException.class,
|
||||
@@ -81,7 +81,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
@Test
|
||||
public void messagingTemplateMustNotBeNull() {
|
||||
// given
|
||||
final RemotePartitioningMasterStepBuilder builder = new RemotePartitioningMasterStepBuilder("step");
|
||||
final RemotePartitioningManagerStepBuilder builder = new RemotePartitioningManagerStepBuilder("step");
|
||||
|
||||
// when
|
||||
final Exception expectedException = Assert.assertThrows(IllegalArgumentException.class,
|
||||
@@ -94,7 +94,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
@Test
|
||||
public void jobExplorerMustNotBeNull() {
|
||||
// given
|
||||
final RemotePartitioningMasterStepBuilder builder = new RemotePartitioningMasterStepBuilder("step");
|
||||
final RemotePartitioningManagerStepBuilder builder = new RemotePartitioningManagerStepBuilder("step");
|
||||
|
||||
// when
|
||||
final Exception expectedException = Assert.assertThrows(IllegalArgumentException.class,
|
||||
@@ -107,7 +107,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
@Test
|
||||
public void pollIntervalMustBeGreaterThanZero() {
|
||||
// given
|
||||
final RemotePartitioningMasterStepBuilder builder = new RemotePartitioningMasterStepBuilder("step");
|
||||
final RemotePartitioningManagerStepBuilder builder = new RemotePartitioningManagerStepBuilder("step");
|
||||
|
||||
// when
|
||||
final Exception expectedException = Assert.assertThrows(IllegalArgumentException.class,
|
||||
@@ -120,7 +120,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
@Test
|
||||
public void eitherOutputChannelOrMessagingTemplateMustBeProvided() {
|
||||
// given
|
||||
RemotePartitioningMasterStepBuilder builder = new RemotePartitioningMasterStepBuilder("step")
|
||||
RemotePartitioningManagerStepBuilder builder = new RemotePartitioningManagerStepBuilder("step")
|
||||
.outputChannel(new DirectChannel())
|
||||
.messagingTemplate(new MessagingTemplate());
|
||||
|
||||
@@ -136,15 +136,15 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
public void testUnsupportedOperationExceptionWhenSpecifyingPartitionHandler() {
|
||||
// given
|
||||
PartitionHandler partitionHandler = Mockito.mock(PartitionHandler.class);
|
||||
final RemotePartitioningMasterStepBuilder builder = new RemotePartitioningMasterStepBuilder("step");
|
||||
final RemotePartitioningManagerStepBuilder builder = new RemotePartitioningManagerStepBuilder("step");
|
||||
|
||||
// when
|
||||
final Exception expectedException = Assert.assertThrows(UnsupportedOperationException.class,
|
||||
() -> builder.partitionHandler(partitionHandler));
|
||||
|
||||
// then
|
||||
assertThat(expectedException).hasMessage("When configuring a master step " +
|
||||
"for remote partitioning using the RemotePartitioningMasterStepBuilder, " +
|
||||
assertThat(expectedException).hasMessage("When configuring a manager step " +
|
||||
"for remote partitioning using the RemotePartitioningManagerStepBuilder, " +
|
||||
"the partition handler will be automatically set to an instance " +
|
||||
"of MessageChannelPartitionHandler. The partition handler must " +
|
||||
"not be provided in this case.");
|
||||
@@ -162,7 +162,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
StepExecutionAggregator stepExecutionAggregator = (result, executions) -> { };
|
||||
|
||||
// when
|
||||
Step step = new RemotePartitioningMasterStepBuilder("masterStep")
|
||||
Step step = new RemotePartitioningManagerStepBuilder("masterStep")
|
||||
.repository(jobRepository)
|
||||
.outputChannel(outputChannel)
|
||||
.partitioner("workerStep", partitioner)
|
||||
@@ -205,7 +205,7 @@ public class RemotePartitioningMasterStepBuilderTests {
|
||||
StepExecutionAggregator stepExecutionAggregator = (result, executions) -> { };
|
||||
|
||||
// when
|
||||
Step step = new RemotePartitioningMasterStepBuilder("masterStep")
|
||||
Step step = new RemotePartitioningManagerStepBuilder("masterStep")
|
||||
.repository(jobRepository)
|
||||
.outputChannel(outputChannel)
|
||||
.partitioner("workerStep", partitioner)
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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
|
||||
*
|
||||
* https://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.test;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameter;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.job.AbstractJob;
|
||||
import org.springframework.batch.core.job.SimpleJob;
|
||||
import org.springframework.batch.core.job.flow.FlowJob;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Base class for testing batch jobs. It provides methods for launching an
|
||||
* entire {@link AbstractJob}, allowing for end to end testing of individual
|
||||
* steps, without having to run every step in the job. Any test classes
|
||||
* inheriting from this class should make sure they are part of an
|
||||
* {@link ApplicationContext}, which is generally expected to be done as part of
|
||||
* the Spring test framework. Furthermore, the {@link ApplicationContext} in
|
||||
* which it is a part of is expected to have one {@link JobLauncher},
|
||||
* {@link JobRepository}, and a single {@link AbstractJob} implementation.
|
||||
*
|
||||
* <p>
|
||||
* This class also provides the ability to run {@link Step}s from a
|
||||
* {@link FlowJob} or {@link SimpleJob} individually. By launching {@link Step}s
|
||||
* within a {@link Job} on their own, end to end testing of individual steps can
|
||||
* be performed without having to run every step in the job.
|
||||
*
|
||||
* <p>
|
||||
* It should be noted that using any of the methods that don't contain
|
||||
* {@link JobParameters} in their signature, will result in one being created
|
||||
* with the current system time as a parameter. This will ensure restartability
|
||||
* when no parameters are provided.
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Dan Garrette
|
||||
* @since 2.0
|
||||
*
|
||||
* @deprecated (from 2.1) use {@link JobLauncherTestUtils} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractJobTests implements ApplicationContextAware {
|
||||
|
||||
/** Logger */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@Autowired
|
||||
private JobLauncher launcher;
|
||||
|
||||
@Autowired
|
||||
private AbstractJob job;
|
||||
|
||||
@Autowired
|
||||
private JobRepository jobRepository;
|
||||
|
||||
private StepRunner stepRunner;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the applicationContext
|
||||
*/
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the job repository which is autowired by type
|
||||
*/
|
||||
public JobRepository getJobRepository() {
|
||||
return jobRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the job which is autowired by type
|
||||
*/
|
||||
public AbstractJob getJob() {
|
||||
return job;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the launcher
|
||||
*/
|
||||
protected JobLauncher getJobLauncher() {
|
||||
return launcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the entire job, including all steps.
|
||||
*
|
||||
* @return JobExecution, so that the test can validate the exit status
|
||||
*
|
||||
* @throws Exception is thrown if error occurs.
|
||||
*/
|
||||
protected JobExecution launchJob() throws Exception {
|
||||
return this.launchJob(this.getUniqueJobParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the entire job, including all steps
|
||||
*
|
||||
* @param jobParameters parameters for the job
|
||||
* @return JobExecution, so that the test can validate the exit status
|
||||
*
|
||||
* @throws Exception is thrown if error occurs.
|
||||
*/
|
||||
protected JobExecution launchJob(JobParameters jobParameters) throws Exception {
|
||||
return getJobLauncher().run(this.job, jobParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new JobParameters object containing only a parameter for the
|
||||
* current timestamp, to ensure that the job instance will be unique.
|
||||
*/
|
||||
protected JobParameters getUniqueJobParameters() {
|
||||
Map<String, JobParameter> parameters = new HashMap<>();
|
||||
parameters.put("timestamp", new JobParameter(new Date().getTime()));
|
||||
return new JobParameters(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method for subclasses to grab a {@link StepRunner} for running
|
||||
* steps by name.
|
||||
*
|
||||
* @return a {@link StepRunner}
|
||||
*/
|
||||
protected StepRunner getStepRunner() {
|
||||
if (this.stepRunner == null) {
|
||||
this.stepRunner = new StepRunner(getJobLauncher(), getJobRepository());
|
||||
}
|
||||
return this.stepRunner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch just the specified step in the job. A unique set of JobParameters
|
||||
* will automatically be generated. An IllegalStateException is thrown if
|
||||
* there is no Step with the given name.
|
||||
*
|
||||
* @param stepName The name of the step to launch
|
||||
* @return JobExecution
|
||||
*/
|
||||
public JobExecution launchStep(String stepName) {
|
||||
return this.launchStep(stepName, this.getUniqueJobParameters(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch just the specified step in the job. A unique set of JobParameters
|
||||
* will automatically be generated. An IllegalStateException is thrown if
|
||||
* there is no Step with the given name.
|
||||
*
|
||||
* @param stepName The name of the step to launch
|
||||
* @param jobExecutionContext An ExecutionContext whose values will be
|
||||
* loaded into the Job ExecutionContext prior to launching the step.
|
||||
* @return JobExecution
|
||||
*/
|
||||
public JobExecution launchStep(String stepName, ExecutionContext jobExecutionContext) {
|
||||
return this.launchStep(stepName, this.getUniqueJobParameters(), jobExecutionContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch just the specified step in the job. An IllegalStateException is
|
||||
* thrown if there is no Step with the given name.
|
||||
*
|
||||
* @param stepName The name of the step to launch
|
||||
* @param jobParameters The JobParameters to use during the launch
|
||||
* @return JobExecution
|
||||
*/
|
||||
public JobExecution launchStep(String stepName, JobParameters jobParameters) {
|
||||
return this.launchStep(stepName, jobParameters, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch just the specified step in the job. An IllegalStateException is
|
||||
* thrown if there is no Step with the given name.
|
||||
*
|
||||
* @param stepName The name of the step to launch
|
||||
* @param jobParameters The JobParameters to use during the launch
|
||||
* @param jobExecutionContext An ExecutionContext whose values will be
|
||||
* loaded into the Job ExecutionContext prior to launching the step.
|
||||
* @return JobExecution
|
||||
*/
|
||||
public JobExecution launchStep(String stepName, JobParameters jobParameters, ExecutionContext jobExecutionContext) {
|
||||
Step step = this.job.getStep(stepName);
|
||||
if (step == null) {
|
||||
step = this.job.getStep(this.job.getName() + "." + stepName);
|
||||
}
|
||||
if (step == null) {
|
||||
throw new IllegalStateException("No Step found with name: [" + stepName + "]");
|
||||
}
|
||||
return getStepRunner().launchStep(step, jobParameters, jobExecutionContext);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009-2014 the original author or authors.
|
||||
* Copyright 2009-2021 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.
|
||||
@@ -27,12 +27,11 @@ import org.springframework.batch.test.sample.SampleTasklet;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.annotation.Repeat;
|
||||
import org.springframework.test.annotation.Repeat;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* This is an abstract test class to be used by test classes to test the
|
||||
* {@link AbstractJobTests} class.
|
||||
* This is an abstract test class.
|
||||
*
|
||||
* @author Dan Garrette
|
||||
* @since 2.0
|
||||
@@ -90,13 +89,13 @@ public abstract class AbstractSampleJobTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Repeat(10)
|
||||
public void testStep3Execution() throws Exception {
|
||||
// logging only, may complete in < 1ms (repeat so that it's likely to for at least one of those times)
|
||||
assertEquals(BatchStatus.COMPLETED, jobLauncherTestUtils.launchStep("step3").getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Repeat(10)
|
||||
public void testStep3Execution() throws Exception {
|
||||
// logging only, may complete in < 1ms (repeat so that it's likely to for at least one of those times)
|
||||
assertEquals(BatchStatus.COMPLETED, jobLauncherTestUtils.launchStep("step3").getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepLaunchJobContextEntry() {
|
||||
ExecutionContext jobContext = new ExecutionContext();
|
||||
jobContext.put("key1", "value1");
|
||||
|
||||
Reference in New Issue
Block a user