/*
* Copyright 2006-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.test.repository;
import static org.junit.Assert.assertEquals;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.dao.MapExecutionContextDao;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
/**
* @author Dave Syer
*
*/
public class ConcurrentMapExecutionContextDaoTests {
private MapExecutionContextDao dao = new MapExecutionContextDao();
private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager();
@Test
public void testSaveUpdate() throws Exception {
StepExecution stepExecution = new StepExecution("step", new JobExecution(11L));
stepExecution.setId(123L);
stepExecution.getExecutionContext().put("foo", "bar");
dao.saveExecutionContext(stepExecution);
ExecutionContext executionContext = dao.getExecutionContext(stepExecution);
assertEquals("bar", executionContext.get("foo"));
}
@Test
public void testTransactionalSaveUpdate() throws Exception {
final StepExecution stepExecution = new StepExecution("step", new JobExecution(11L));
stepExecution.setId(123L);
new TransactionTemplate(transactionManager).execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus status) {
stepExecution.getExecutionContext().put("foo", "bar");
dao.saveExecutionContext(stepExecution);
return null;
}
});
ExecutionContext executionContext = dao.getExecutionContext(stepExecution);
assertEquals("bar", executionContext.get("foo"));
}
@Test
public void testConcurrentTransactionalSaveUpdate() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletionService<StepExecution> completionService = new ExecutorCompletionService<StepExecution>(executor);
final int outerMax = 10;
final int innerMax = 100;
for (int i = 0; i < outerMax; i++) {
final StepExecution stepExecution1 = new StepExecution("step", new JobExecution(11L));
stepExecution1.setId(123L + i);
final StepExecution stepExecution2 = new StepExecution("step", new JobExecution(11L));
stepExecution2.setId(1234L + i);
completionService.submit(new Callable<StepExecution>() {
@Override
public StepExecution call() throws Exception {
for (int i = 0; i < innerMax; i++) {
String value = "bar" + i;
saveAndAssert(stepExecution1, value);
}
return stepExecution1;
}
});
completionService.submit(new Callable<StepExecution>() {
@Override
public StepExecution call() throws Exception {
for (int i = 0; i < innerMax; i++) {
String value = "spam" + i;
saveAndAssert(stepExecution2, value);
}
return stepExecution2;
}
});
completionService.take().get();
completionService.take().get();
}
executor.shutdown();
}
private void saveAndAssert(final StepExecution stepExecution, final String value) {
new TransactionTemplate(transactionManager).execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus status) {
stepExecution.getExecutionContext().put("foo", value);
dao.saveExecutionContext(stepExecution);
return null;
}
});
ExecutionContext executionContext = dao.getExecutionContext(stepExecution);
Assert.state(executionContext != null, "Lost insert: null executionContext at value=" + value);
String foo = executionContext.getString("foo");
Assert.state(value.equals(foo), "Lost update: wrong value=" + value + " (found " + foo + ") for id="
+ stepExecution.getId());
}
}