Remove deprecated APIs

Resolves #3836
This commit is contained in:
Mahmoud Ben Hassine
2021-08-17 20:55:08 +02:00
parent f8bdf5521e
commit bb3809cf55
37 changed files with 217 additions and 2712 deletions

View File

@@ -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
*

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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 {
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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());
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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>

View File

@@ -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");
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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.");
}
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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>).

View File

@@ -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");
}
}

View File

@@ -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];
}
}

View File

@@ -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();
}
}

View File

@@ -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.
*

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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.
*/

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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.");
}
}

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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");