├── README
├── build.gradle
├── gradle.properties
├── pom.xml
└── src
├── main
├── java
│ └── org
│ │ └── springframework
│ │ ├── batch
│ │ └── mongo
│ │ │ ├── config
│ │ │ ├── ApplicationConfiguration.java
│ │ │ ├── Database.java
│ │ │ ├── MongoDbFactoryBean.java
│ │ │ └── MongoDbInitializer.java
│ │ │ └── dao
│ │ │ ├── AbstractMongoDao.java
│ │ │ ├── MongoExecutionContextDao.java
│ │ │ ├── MongoJobExecutionDao.java
│ │ │ ├── MongoJobInstanceDao.java
│ │ │ └── MongoStepExecutionDao.java
│ │ └── javaconfig
│ │ └── util
│ │ └── ConfigurationSupport.java
└── resources
│ ├── application-config.xml
│ ├── batch.properties
│ └── logback.xml
└── test
└── java
└── org
└── springframework
└── batch
└── mongo
├── config
├── ApplicationTestConfiguration.java
└── JobConfiguration.java
├── dao
├── AbstractExecutionContextDaoTests.java
├── AbstractJobDaoTests.java
├── AbstractJobExecutionDaoTests.java
├── AbstractJobInstanceDaoTests.java
├── AbstractStepExecutionDaoTests.java
├── MongoDaoTests.java
├── MongoExecutionContextDaoTests.java
├── MongoJobDaoTests.java
├── MongoJobExecutionDaoTests.java
├── MongoJobInstanceDaoTests.java
└── MongoStepExecutionDaoTests.java
├── example
├── ExampleItemReader.java
├── ExampleItemReaderTests.java
├── ExampleItemWriter.java
├── ExampleItemWriterTests.java
└── ExampleJobConfigurationTests.java
├── step
└── StepSupport.java
└── util
└── Shutdown.java
/README:
--------------------------------------------------------------------------------
1 | Spring Batch meta-data persistency DAOs implementation over MongoDB. For more details please see http://jbaruch.wordpress.com/2010/04/27/integrating-mongodb-with-spring-batch/
2 |
3 | Here's how:
4 | 1. Get MongoDB - http://www.mongodb.org/display/DOCS/Downloads
5 | 2. Get Gradle - http://dist.codehaus.org/gradle
6 | 3. (Optional) Set mongoDB home and startMongo flag in gradle.properties. If you do so, database will automatically start before tests and shutdown after. If you're on *nix and installed MongoDB distribution, it will be found without setting MongoDB home.
7 | 4. Run 'gradle test assemble'
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'maven'
3 |
4 | group = 'org.springframework.batch'
5 | version = '1.0-SNAPSHOT'
6 |
7 | configurations.compile.transitive = true
8 |
9 | sourceCompatibility = 1.5
10 | targetCompatibility = 1.5
11 |
12 | repositories {
13 | mavenRepo urls: ["http://repo.jfrog.org/artifactory/libs-releases"]
14 | mavenRepo urls: ["http://repo.jfrog.org/artifactory/libs-snapshots"]
15 | }
16 | dependencies {
17 | compile "org.slf4j:slf4j-api:1.5.11"
18 | compile "ch.qos.logback:logback-classic:0.9.18"
19 | compile "org.slf4j:log4j-over-slf4j:1.5.11"
20 | compile "org.slf4j:jcl-over-slf4j:1.5.11"
21 | compile "cglib:cglib:2.2"
22 | compile "org.springframework:org.springframework.core:3.0.2.RELEASE"
23 | compile "org.springframework:org.springframework.aop:3.0.2.RELEASE"
24 | compile "org.springframework:org.springframework.context:3.0.2.RELEASE"
25 | compile "org.springframework:org.springframework.transaction:3.0.2.RELEASE"
26 | compile "org.aspectj:aspectjrt:1.6.8"
27 | compile "org.aspectj:aspectjweaver:1.6.8"
28 | compile "org.springframework:org.springframework.beans:3.0.2.RELEASE"
29 | compile "org.springframework:org.springframework.asm:3.0.2.RELEASE"
30 | compile "org.springframework:org.springframework.expression:3.0.2.RELEASE"
31 | compile("org.springframework.batch:spring-batch-core:2.1.2.RELEASE") {
32 | exclude(module: 'spring-tx')
33 | exclude(module: 'spring-beans')
34 | exclude(module: 'spring-context')
35 | exclude(module: 'spring-aop')
36 | exclude(module: 'spring-core')
37 | }
38 | compile("org.springframework.batch:spring-batch-infrastructure:2.1.2.RELEASE") {
39 | exclude(module: 'spring-core')
40 | exclude(module: 'commons-logging')
41 | }
42 | compile "org.mongodb:mongo-java-driver:2.3"
43 | compile "commons-io:commons-io:1.4"
44 | testCompile "junit:junit:4.8.1"
45 | testCompile "org.springframework:org.springframework.test:3.0.2.RELEASE"
46 | testCompile("org.springframework.batch:spring-batch-test:2.1.2.RELEASE") {
47 | exclude(module: 'spring-test')
48 | exclude(module: 'spring-jdbc')
49 | exclude(module: 'commons-io')
50 | exclude(module: 'commons-collections')
51 | }
52 | }
53 |
54 | task replacePoms(dependsOn: install) << {
55 | def pomsDir = new File(project.buildDir, "poms")
56 | def defaultPomName = "pom-default.xml"
57 | def defaultPom = new File(pomsDir, defaultPomName)
58 | if (defaultPom.exists()) {
59 | File pomFile = new File(project.projectDir, "pom.xml")
60 | if (pomFile.exists()) {
61 | pomFile.renameTo(new File(project.projectDir, "pom.xml.bak"))
62 | }
63 | project.copy {
64 | from(pomsDir) {
65 | include defaultPomName
66 | rename defaultPomName, 'pom.xml'
67 | }
68 | into(project.projectDir)
69 | }
70 | }
71 | }
72 |
73 | test.doFirst {
74 | if (project.hasProperty('startMongo') && project.startMongo) {
75 | def windows = ((String) System.properties['os.name']).toLowerCase().contains("win")
76 | File executable
77 | project.mongoExecFound = false
78 | if (project.hasProperty('mongoHome')) {
79 | executable = new File(project.mongoHome + "/bin/" + "mongod" + (windows ? ".exe" : ""))
80 | project.mongoExecFound = executable.isFile();
81 | }
82 | if (!project.mongoExecFound && !windows) {
83 | executable = new File('/usr/bin/mongod');
84 | project.mongoExecFound = executable.isFile();
85 | }
86 | if (project.mongoExecFound) {
87 | logger.info("Going to startup MongoDB daemon: ${executable} ...")
88 | ant.exec(spawn: true, executable: executable.getAbsolutePath())
89 | }
90 | }
91 | }
92 |
93 | test.doLast {
94 | if (project.mongoExecFound) {
95 | logger.info('taking MongoDB down...')
96 | //Shutdown the db. Can't just call the class since script's classpath can't use project classes
97 | ant.java(classname: 'org.springframework.batch.mongo.util.Shutdown',
98 | fork: true,
99 | classpath: "${sourceSets.test.runtimeClasspath.asPath}")
100 | }
101 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #MongoDB installation directory.
2 | #Mandatory for Windows (if you want the test to start MongoDB), on *Nix will search in ... if not set.
3 | mongoHome=C:/Users/JBaruch/lib/mongodb-win32-i386-1.4.1
4 |
5 | #Try to start MongoDB before tests and shut it down after.
6 | startMongo=true
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 | org.springframework.batch
7 | spring-batch-over-mongodb
8 | 1.0-SNAPSHOT
9 | jar
10 | Spring Batch over MongoDB
11 | Use Gradle for build. This pom is provided for IDE integration only.
12 |
13 | http://github.com/jbaruch/springbatch-over-mongodb
14 |
15 |
16 | 3.0.2.RELEASE
17 | 2.1.0.RELEASE
18 | 1.6.8
19 | 1.5.11
20 |
21 |
22 |
23 |
24 | org.slf4j
25 | slf4j-api
26 | ${slf4j.version}
27 |
28 |
29 | ch.qos.logback
30 | logback-classic
31 | 0.9.18
32 |
33 |
34 | org.slf4j
35 | log4j-over-slf4j
36 | ${slf4j.version}
37 |
38 |
39 | org.slf4j
40 | jcl-over-slf4j
41 | ${slf4j.version}
42 |
43 |
44 |
45 |
46 | junit
47 | junit
48 | 4.8.1
49 | test
50 |
51 |
52 | org.springframework
53 | org.springframework.test
54 | ${spring.framework.version}
55 | test
56 |
57 |
58 | org.springframework.batch
59 | spring-batch-test
60 | ${spring.batch.version}
61 | test
62 |
63 |
64 | org.springframework
65 | spring-test
66 |
67 |
68 | org.springframework
69 | spring-jdbc
70 |
71 |
72 | commons-io
73 | commons-io
74 |
75 |
76 | commons-collections
77 | commons-collections
78 |
79 |
80 |
81 |
82 |
83 |
84 | cglib
85 | cglib
86 | 2.2
87 |
88 |
89 | org.springframework
90 | org.springframework.core
91 | ${spring.framework.version}
92 |
93 |
94 | org.springframework
95 | org.springframework.aop
96 | ${spring.framework.version}
97 |
98 |
99 | org.springframework
100 | org.springframework.context
101 | ${spring.framework.version}
102 |
103 |
104 | org.springframework
105 | org.springframework.transaction
106 | ${spring.framework.version}
107 |
108 |
109 | org.aspectj
110 | aspectjrt
111 | ${aspectj.version}
112 |
113 |
114 | org.aspectj
115 | aspectjweaver
116 | ${aspectj.version}
117 |
118 |
119 | org.springframework
120 | org.springframework.beans
121 | 3.0.2.RELEASE
122 |
123 |
124 | org.springframework
125 | org.springframework.asm
126 | 3.0.2.RELEASE
127 |
128 |
129 | org.springframework
130 | org.springframework.expression
131 | 3.0.2.RELEASE
132 |
133 |
134 |
135 |
136 | org.springframework.batch
137 | spring-batch-core
138 | ${spring.batch.version}
139 |
140 |
141 | org.springframework
142 | spring-tx
143 |
144 |
145 | org.springframework
146 | spring-beans
147 |
148 |
149 | org.springframework
150 | spring-context
151 |
152 |
153 | org.springframework
154 | spring-aop
155 |
156 |
157 | org.springframework
158 | spring-core
159 |
160 |
161 |
162 |
163 | org.springframework.batch
164 | spring-batch-infrastructure
165 | ${spring.batch.version}
166 |
167 |
168 | org.springframework
169 | spring-core
170 |
171 |
172 | commons-logging
173 | commons-logging
174 |
175 |
176 |
177 |
178 |
179 |
180 | org.mongodb
181 | mongo-java-driver
182 | 2.3
183 |
184 |
185 |
186 |
187 | commons-io
188 | commons-io
189 | 1.4
190 |
191 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/config/ApplicationConfiguration.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.config;
2 |
3 | import com.mongodb.DB;
4 | import com.mongodb.Mongo;
5 | import org.springframework.batch.core.JobParametersIncrementer;
6 | import org.springframework.batch.core.configuration.JobRegistry;
7 | import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
8 | import org.springframework.batch.core.configuration.support.MapJobRegistry;
9 | import org.springframework.batch.core.explore.JobExplorer;
10 | import org.springframework.batch.core.explore.support.SimpleJobExplorer;
11 | import org.springframework.batch.core.launch.support.RunIdIncrementer;
12 | import org.springframework.batch.core.launch.support.SimpleJobLauncher;
13 | import org.springframework.batch.core.launch.support.SimpleJobOperator;
14 | import org.springframework.batch.core.repository.JobRepository;
15 | import org.springframework.batch.core.repository.dao.ExecutionContextDao;
16 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
17 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
18 | import org.springframework.batch.core.repository.dao.StepExecutionDao;
19 | import org.springframework.batch.core.repository.support.SimpleJobRepository;
20 | import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
21 | import org.springframework.beans.factory.annotation.Autowired;
22 | import org.springframework.beans.factory.annotation.Value;
23 | import org.springframework.context.annotation.Bean;
24 | import org.springframework.context.annotation.Configuration;
25 | import org.springframework.core.task.TaskExecutor;
26 | import org.springframework.javaconfig.util.ConfigurationSupport;
27 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
28 | import org.springframework.transaction.PlatformTransactionManager;
29 |
30 | import java.net.UnknownHostException;
31 |
32 | /**
33 | * Created by IntelliJ IDEA.
34 | *
35 | * @author JBaruch
36 | * @since 19-Apr-2010
37 | */
38 | @Configuration
39 | public class ApplicationConfiguration {
40 |
41 | @Value("${app.db.name}")
42 | private String appDbName;
43 |
44 | @Value("${batch.db.name}")
45 | private String batchDbName;
46 |
47 | @Value("${step.thread.core.pool.size}")
48 | private int corePoolSize;
49 |
50 | @Value("${step.thread.max.pool.size}")
51 | private int maxPoolSize;
52 |
53 |
54 | @Autowired
55 | private ConfigurationSupport configurationSupport;
56 |
57 | @Autowired
58 | private ExecutionContextDao executionContextDao;
59 |
60 | @Autowired
61 | private JobExecutionDao jobExecutionDao;
62 |
63 | @Autowired
64 | private JobInstanceDao jobInstanceDao;
65 |
66 | @Autowired
67 | private StepExecutionDao stepExecutionDao;
68 |
69 | public static final String DOT_ESCAPE_STRING = "\\{dot\\}";
70 | public static final String DOT_STRING = "\\.";
71 |
72 |
73 | @Bean
74 | public SimpleJobOperator jobOperator() {
75 | SimpleJobOperator jobOperator = new SimpleJobOperator();
76 | jobOperator.setJobLauncher(jobLauncher());
77 | jobOperator.setJobExplorer(jobExplorer());
78 | jobOperator.setJobRepository(jobRepository());
79 | jobOperator.setJobRegistry(jobRegistry());
80 | return jobOperator;
81 | }
82 |
83 | @Bean
84 | public JobExplorer jobExplorer() {
85 | return new SimpleJobExplorer(jobInstanceDao, jobExecutionDao, stepExecutionDao, executionContextDao);
86 | }
87 |
88 | @Bean
89 | public JobRegistry jobRegistry() {
90 | return new MapJobRegistry();
91 | }
92 |
93 | @Bean
94 | JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
95 | JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
96 | postProcessor.setJobRegistry(jobRegistry());
97 | return postProcessor;
98 | }
99 |
100 | @Bean
101 | public SimpleJobLauncher jobLauncher() {
102 | SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
103 | jobLauncher.setJobRepository(jobRepository());
104 | return jobLauncher;
105 | }
106 |
107 | @Bean
108 | public JobRepository jobRepository() {
109 | return new SimpleJobRepository(jobInstanceDao, jobExecutionDao, stepExecutionDao, executionContextDao);
110 | }
111 |
112 | @Bean
113 | public TaskExecutor taskExecutor() {
114 | ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
115 | taskExecutor.setCorePoolSize(corePoolSize);
116 | taskExecutor.setMaxPoolSize(maxPoolSize);
117 | return taskExecutor;
118 | }
119 |
120 | @Bean
121 | public JobParametersIncrementer jobParametersIncrementer() {
122 | return new RunIdIncrementer();
123 | }
124 |
125 | @Bean
126 | @Database(Database.Purpose.APPLICATION)
127 | public DB applicationDb() throws UnknownHostException {
128 | return mongo().getDB(appDbName);
129 | }
130 |
131 | @Bean
132 | @Database(Database.Purpose.BATCH)
133 | public DB batchDb() throws UnknownHostException {
134 | return mongo().getDB(batchDbName);
135 | }
136 |
137 | @Bean
138 | public Mongo mongo() throws UnknownHostException {
139 | return new Mongo();
140 | }
141 |
142 | @Bean
143 | public PlatformTransactionManager transactionManager() {
144 | return new ResourcelessTransactionManager();
145 | }
146 |
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/config/Database.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.config;
2 |
3 | import org.springframework.beans.factory.annotation.Qualifier;
4 |
5 | import java.lang.annotation.RetentionPolicy;
6 |
7 | /**
8 | * Created by IntelliJ IDEA.
9 | *
10 | * @author Baruch S.
11 | * @since Apr 18, 2010
12 | */
13 | @java.lang.annotation.Documented
14 | @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
15 | @Qualifier
16 | public @interface Database {
17 | Purpose value();
18 |
19 | public enum Purpose {
20 | BATCH, APPLICATION
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/config/MongoDbFactoryBean.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.config;
2 |
3 | import com.mongodb.DB;
4 | import com.mongodb.Mongo;
5 | import org.springframework.beans.factory.FactoryBean;
6 | import org.springframework.beans.factory.InitializingBean;
7 |
8 | import java.net.UnknownHostException;
9 |
10 | /**
11 | * com.mongodb.DB object factory bean for usage in Spring xml configuration.
12 | * Created by IntelliJ IDEA.
13 | *
14 | * @author Baruch S.
15 | * @since Apr 28, 2010
16 | */
17 | public class MongoDbFactoryBean implements FactoryBean, InitializingBean {
18 |
19 | private String dbName;
20 | private Mongo mongo;
21 | private DB db;
22 |
23 | public MongoDbFactoryBean(String dbName, String mongoHost, int mongoPort) throws UnknownHostException {
24 | this.dbName = dbName;
25 | this.mongo = new Mongo(mongoHost, mongoPort);
26 | }
27 |
28 | public Object getObject() throws Exception {
29 | return db;
30 | }
31 |
32 | public Class getObjectType() {
33 | return DB.class;
34 | }
35 |
36 | public boolean isSingleton() {
37 | return true;
38 | }
39 |
40 | public void afterPropertiesSet() throws Exception {
41 | db = mongo.getDB(dbName);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/config/MongoDbInitializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2007 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.batch.mongo.config;
18 |
19 | import com.mongodb.DB;
20 | import org.apache.commons.logging.Log;
21 | import org.apache.commons.logging.LogFactory;
22 | import org.springframework.beans.factory.InitializingBean;
23 | import org.springframework.util.Assert;
24 |
25 | public class MongoDbInitializer implements InitializingBean {
26 |
27 | private boolean initialize = false;
28 |
29 | private DB db;
30 |
31 | private Log logger = LogFactory.getLog(getClass());
32 |
33 | public void setInitialize(boolean initialize) {
34 | this.initialize = initialize;
35 | }
36 |
37 | public void setDb(DB db) {
38 | this.db = db;
39 | }
40 |
41 | public void afterPropertiesSet() throws Exception {
42 | Assert.notNull(db);
43 | if (initialize) {
44 | try {
45 | db.dropDatabase();
46 | logger.debug("Database dropped");
47 | }
48 | catch (Exception e) {
49 | logger.debug("Could not drop database", e);
50 | }
51 | }
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/dao/AbstractMongoDao.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.BasicDBObject;
4 | import com.mongodb.DB;
5 | import com.mongodb.DBCollection;
6 | import com.mongodb.DBObject;
7 | import org.springframework.batch.mongo.config.Database;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 |
10 | /**
11 | * Created by IntelliJ IDEA.
12 | *
13 | * @author Baruch S.
14 | * @since Apr 15, 2010
15 | */
16 | public abstract class AbstractMongoDao {
17 |
18 | protected DB db;
19 | protected static final String UPDATED_EXISTING_STATUS = "updatedExisting";
20 | protected static final String VERSION_KEY = "version";
21 | protected static final String START_TIME_KEY = "startTime";
22 | protected static final String END_TIME_KEY = "endTime";
23 | protected static final String EXIT_CODE_KEY = "exitCode";
24 | protected static final String EXIT_MESSAGE_KEY = "exitMessage";
25 | protected static final String LAST_UPDATED_KEY = "lastUpdated";
26 | protected static final String STATUS_KEY = "status";
27 | protected static final String SEQUENCES_COLLECTION_NAME = "Sequences";
28 | public static final String ID_KEY = "_id";
29 | public static final String NS_KEY = "_ns";
30 | public static final String DOT_ESCAPE_STRING = "\\{dot\\}";
31 | public static final String DOT_STRING = "\\.";
32 |
33 | @Autowired
34 | @Database(Database.Purpose.BATCH)
35 | public void setDb(DB db) {
36 | this.db = db;
37 | }
38 |
39 | protected abstract DBCollection getCollection();
40 |
41 | protected Long getNextId(String name) {
42 | DBCollection collection = db.getCollection(SEQUENCES_COLLECTION_NAME);
43 | BasicDBObject sequence = new BasicDBObject("name", name);
44 | collection.update(sequence, new BasicDBObject("$inc", new BasicDBObject("value", 1L)), true, false);
45 | return (Long) collection.findOne(sequence).get("value");
46 | }
47 |
48 | protected void removeSystemFields(DBObject dbObject) {
49 | dbObject.removeField(ID_KEY);
50 | dbObject.removeField(NS_KEY);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/dao/MongoExecutionContextDao.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.BasicDBObject;
4 | import com.mongodb.BasicDBObjectBuilder;
5 | import com.mongodb.DBCollection;
6 | import com.mongodb.DBObject;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.batch.core.JobExecution;
10 | import org.springframework.batch.core.StepExecution;
11 | import org.springframework.batch.core.repository.dao.ExecutionContextDao;
12 | import org.springframework.batch.item.ExecutionContext;
13 | import org.springframework.stereotype.Repository;
14 | import org.springframework.util.Assert;
15 | import org.springframework.util.NumberUtils;
16 |
17 | import javax.annotation.PostConstruct;
18 | import java.math.BigDecimal;
19 | import java.math.BigInteger;
20 | import java.util.Map;
21 |
22 | /**
23 | * Created by IntelliJ IDEA.
24 | *
25 | * @author Baruch S.
26 | * @since Apr 15, 2010
27 | */
28 | @Repository
29 | public class MongoExecutionContextDao extends AbstractMongoDao implements ExecutionContextDao {
30 | private static final String STEP_EXECUTION_ID_KEY = "stepExecutionId";
31 | private static final String JOB_EXECUTION_ID_KEY = "jobExecutionId";
32 | protected static final String TYPE_SUFFIX = "_TYPE";
33 | private static final Logger LOG = LoggerFactory.getLogger(MongoExecutionContextDao.class);
34 |
35 | @PostConstruct
36 | public void init() {
37 | getCollection().ensureIndex(BasicDBObjectBuilder.start().add(STEP_EXECUTION_ID_KEY, 1).add(JOB_EXECUTION_ID_KEY, 1).get());
38 | }
39 |
40 | public ExecutionContext getExecutionContext(JobExecution jobExecution) {
41 | return getExecutionContext(JOB_EXECUTION_ID_KEY, jobExecution.getId());
42 | }
43 |
44 | public ExecutionContext getExecutionContext(StepExecution stepExecution) {
45 | return getExecutionContext(STEP_EXECUTION_ID_KEY, stepExecution.getId());
46 | }
47 |
48 | public void saveExecutionContext(JobExecution jobExecution) {
49 | saveOrUpdateExecutionContext(JOB_EXECUTION_ID_KEY, jobExecution.getId(), jobExecution.getExecutionContext());
50 | }
51 |
52 | public void saveExecutionContext(StepExecution stepExecution) {
53 | saveOrUpdateExecutionContext(STEP_EXECUTION_ID_KEY, stepExecution.getId(), stepExecution.getExecutionContext());
54 | }
55 |
56 | public void updateExecutionContext(JobExecution jobExecution) {
57 | saveOrUpdateExecutionContext(JOB_EXECUTION_ID_KEY, jobExecution.getId(), jobExecution.getExecutionContext());
58 | }
59 |
60 | public void updateExecutionContext(StepExecution stepExecution) {
61 | saveOrUpdateExecutionContext(STEP_EXECUTION_ID_KEY, stepExecution.getId(), stepExecution.getExecutionContext());
62 | }
63 |
64 | private void saveOrUpdateExecutionContext(String executionIdKey, Long executionId, ExecutionContext executionContext) {
65 | Assert.notNull(executionId, "ExecutionId must not be null.");
66 | Assert.notNull(executionContext, "The ExecutionContext must not be null.");
67 |
68 | DBObject dbObject = new BasicDBObject(executionIdKey, executionId);
69 | for (Map.Entry entry : executionContext.entrySet()) {
70 | Object value = entry.getValue();
71 | String key = entry.getKey();
72 | dbObject.put(key, value);
73 | if (value instanceof BigDecimal || value instanceof BigInteger) {
74 | dbObject.put(key + TYPE_SUFFIX, value.getClass().getName());
75 | }
76 | }
77 | getCollection().update(new BasicDBObject(executionIdKey, executionId), dbObject, true, false);
78 | }
79 |
80 | @SuppressWarnings({"unchecked"})
81 | private ExecutionContext getExecutionContext(String executionIdKey, Long executionId) {
82 | Assert.notNull(executionId, "ExecutionId must not be null.");
83 | DBObject result = getCollection().findOne(new BasicDBObject(executionIdKey, executionId));
84 | ExecutionContext executionContext = new ExecutionContext();
85 | if (result != null) {
86 | result.removeField(executionIdKey);
87 | removeSystemFields(result);
88 | for (String key : result.keySet()) {
89 | Object value = result.get(key);
90 | String type = (String) result.get(key + TYPE_SUFFIX);
91 | if (type != null && Number.class.isAssignableFrom(value.getClass())) {
92 | try {
93 | value = NumberUtils.convertNumberToTargetClass((Number) value, (Class extends Number>) Class.forName(type));
94 | } catch (Exception e) {
95 | LOG.warn("Failed to convert {} to {}", key, type);
96 | }
97 | }
98 | executionContext.put(key, value);
99 | }
100 | }
101 | return executionContext;
102 | }
103 |
104 | protected DBCollection getCollection() {
105 | return db.getCollection(ExecutionContext.class.getSimpleName());
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/dao/MongoJobExecutionDao.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.*;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.batch.core.BatchStatus;
7 | import org.springframework.batch.core.ExitStatus;
8 | import org.springframework.batch.core.JobExecution;
9 | import org.springframework.batch.core.JobInstance;
10 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
11 | import org.springframework.batch.core.repository.dao.NoSuchObjectException;
12 | import org.springframework.dao.OptimisticLockingFailureException;
13 | import org.springframework.stereotype.Repository;
14 | import org.springframework.util.Assert;
15 |
16 | import javax.annotation.PostConstruct;
17 | import java.util.*;
18 |
19 | import static com.mongodb.BasicDBObjectBuilder.start;
20 | import static org.springframework.batch.mongo.dao.MongoJobInstanceDao.JOB_INSTANCE_ID_KEY;
21 | import static org.springframework.batch.mongo.dao.MongoJobInstanceDao.jobInstanceIdObj;
22 |
23 | /**
24 | * Created by IntelliJ IDEA.
25 | *
26 | * @author Baruch S.
27 | * @since Apr 15, 2010
28 | */
29 | @Repository
30 | public class MongoJobExecutionDao extends AbstractMongoDao implements JobExecutionDao {
31 |
32 | public static final String JOB_EXECUTION_ID_KEY = "jobExecutionId";
33 | private static final String CREATE_TIME_KEY = "createTime";
34 | private static final Logger LOG = LoggerFactory.getLogger(MongoJobExecutionDao.class);
35 |
36 | @PostConstruct
37 | public void init() {
38 | getCollection().ensureIndex(BasicDBObjectBuilder.start().add(JOB_EXECUTION_ID_KEY, 1).add(JOB_INSTANCE_ID_KEY, 1).get());
39 | }
40 |
41 | public void saveJobExecution(JobExecution jobExecution) {
42 | validateJobExecution(jobExecution);
43 | jobExecution.incrementVersion();
44 | Long id = getNextId(JobExecution.class.getSimpleName());
45 | save(jobExecution, id);
46 | }
47 |
48 | private void save(JobExecution jobExecution, Long id) {
49 | jobExecution.setId(id);
50 | DBObject object = toDbObjectWithoutVersion(jobExecution);
51 | object.put(VERSION_KEY, jobExecution.getVersion());
52 | getCollection().save(object);
53 | }
54 |
55 | private DBObject toDbObjectWithoutVersion(JobExecution jobExecution) {
56 | return start()
57 | .add(JOB_EXECUTION_ID_KEY, jobExecution.getId())
58 | .add(JOB_INSTANCE_ID_KEY, jobExecution.getJobId())
59 | .add(START_TIME_KEY, jobExecution.getStartTime())
60 | .add(END_TIME_KEY, jobExecution.getEndTime())
61 | .add(STATUS_KEY, jobExecution.getStatus().toString())
62 | .add(EXIT_CODE_KEY, jobExecution.getExitStatus().getExitCode())
63 | .add(EXIT_MESSAGE_KEY, jobExecution.getExitStatus().getExitDescription())
64 | .add(CREATE_TIME_KEY, jobExecution.getCreateTime())
65 | .add(LAST_UPDATED_KEY, jobExecution.getLastUpdated()).get();
66 | }
67 |
68 |
69 | private void validateJobExecution(JobExecution jobExecution) {
70 |
71 | Assert.notNull(jobExecution);
72 | Assert.notNull(jobExecution.getJobId(), "JobExecution Job-Id cannot be null.");
73 | Assert.notNull(jobExecution.getStatus(), "JobExecution status cannot be null.");
74 | Assert.notNull(jobExecution.getCreateTime(), "JobExecution create time cannot be null");
75 | }
76 |
77 | public synchronized void updateJobExecution(JobExecution jobExecution) {
78 | validateJobExecution(jobExecution);
79 |
80 | Long jobExecutionId = jobExecution.getId();
81 | Assert.notNull(jobExecutionId,
82 | "JobExecution ID cannot be null. JobExecution must be saved before it can be updated");
83 |
84 | Assert.notNull(jobExecution.getVersion(),
85 | "JobExecution version cannot be null. JobExecution must be saved before it can be updated");
86 |
87 | Integer version = jobExecution.getVersion() + 1;
88 |
89 | if (getCollection().findOne(jobExecutionIdObj(jobExecutionId)) == null) {
90 | throw new NoSuchObjectException("Invalid JobExecution, ID " + jobExecutionId + " not found.");
91 | }
92 |
93 | DBObject object = toDbObjectWithoutVersion(jobExecution);
94 | object.put(VERSION_KEY, version);
95 | getCollection().update(start()
96 | .add(JOB_EXECUTION_ID_KEY, jobExecutionId)
97 | .add(VERSION_KEY, jobExecution.getVersion()).get(),
98 | object);
99 |
100 | // Avoid concurrent modifications...
101 | DBObject lastError = db.getLastError();
102 | if (!((Boolean) lastError.get(UPDATED_EXISTING_STATUS))) {
103 | LOG.error("Update returned status {}", lastError);
104 | DBObject existingJobExecution = getCollection().findOne(jobExecutionIdObj(jobExecutionId), new BasicDBObject(VERSION_KEY, 1));
105 | if (existingJobExecution == null) {
106 | throw new IllegalArgumentException("Can't update this jobExecution, it was never saved.");
107 | }
108 | Integer curentVersion = ((Integer) existingJobExecution.get(VERSION_KEY));
109 | throw new OptimisticLockingFailureException("Attempt to update job execution id="
110 | + jobExecutionId + " with wrong version (" + jobExecution.getVersion()
111 | + "), where current version is " + curentVersion);
112 | }
113 |
114 | jobExecution.incrementVersion();
115 | }
116 |
117 | public List findJobExecutions(JobInstance jobInstance) {
118 | Assert.notNull(jobInstance, "Job cannot be null.");
119 | Long id = jobInstance.getId();
120 | Assert.notNull(id, "Job Id cannot be null.");
121 | DBCursor dbCursor = getCollection().find(jobInstanceIdObj(id)).sort(new BasicDBObject(JOB_EXECUTION_ID_KEY, -1));
122 | List result = new ArrayList();
123 | while (dbCursor.hasNext()) {
124 | DBObject dbObject = dbCursor.next();
125 | result.add(mapJobExecution(jobInstance, dbObject));
126 | }
127 | return result;
128 | }
129 |
130 | public JobExecution getLastJobExecution(JobInstance jobInstance) {
131 | Long id = jobInstance.getId();
132 |
133 | DBCursor dbCursor = getCollection().find(jobInstanceIdObj(id)).sort(new BasicDBObject(CREATE_TIME_KEY, -1)).limit(1);
134 | if (!dbCursor.hasNext()) {
135 | return null;
136 | } else {
137 | DBObject singleResult = dbCursor.next();
138 | if (dbCursor.hasNext()) {
139 | throw new IllegalStateException("There must be at most one latest job execution");
140 | }
141 | return mapJobExecution(jobInstance, singleResult);
142 | }
143 | }
144 |
145 | public Set findRunningJobExecutions(String jobName) {
146 | DBCursor instancesCursor = db.getCollection(JobInstance.class.getSimpleName()).find(new BasicDBObject(MongoJobInstanceDao.JOB_NAME_KEY, jobName), jobInstanceIdObj(1L));
147 | List ids = new ArrayList();
148 | while (instancesCursor.hasNext()) {
149 | ids.add((Long) instancesCursor.next().get(JOB_INSTANCE_ID_KEY));
150 | }
151 |
152 | DBCursor dbCursor = getCollection().find(BasicDBObjectBuilder.start()
153 | .add(JOB_INSTANCE_ID_KEY, new BasicDBObject("$in", ids.toArray()))
154 | .add(END_TIME_KEY, null).get()).sort(jobExecutionIdObj(-1L));
155 | Set result = new HashSet();
156 | while (dbCursor.hasNext()) {
157 | result.add(mapJobExecution(dbCursor.next()));
158 | }
159 | return result;
160 | }
161 |
162 | public JobExecution getJobExecution(Long executionId) {
163 | return mapJobExecution(getCollection().findOne(jobExecutionIdObj(executionId)));
164 | }
165 |
166 | public void synchronizeStatus(JobExecution jobExecution) {
167 | Long id = jobExecution.getId();
168 | DBObject jobExecutionObject = getCollection().findOne(jobExecutionIdObj(id));
169 | int currentVersion = jobExecutionObject != null ? ((Integer) jobExecutionObject.get(VERSION_KEY)) : 0;
170 | if (currentVersion != jobExecution.getVersion()) {
171 | if (jobExecutionObject == null) {
172 | save(jobExecution, id);
173 | jobExecutionObject = getCollection().findOne(jobExecutionIdObj(id));
174 | }
175 | String status = (String) jobExecutionObject.get(STATUS_KEY);
176 | jobExecution.upgradeStatus(BatchStatus.valueOf(status));
177 | jobExecution.setVersion(currentVersion);
178 | }
179 | }
180 |
181 | static BasicDBObject jobExecutionIdObj(Long id) {
182 | return new BasicDBObject(JOB_EXECUTION_ID_KEY, id);
183 | }
184 |
185 | @Override
186 | protected DBCollection getCollection() {
187 | return db.getCollection(JobExecution.class.getSimpleName());
188 | }
189 |
190 | private JobExecution mapJobExecution(DBObject dbObject) {
191 | return mapJobExecution(null, dbObject);
192 | }
193 |
194 | private JobExecution mapJobExecution(JobInstance jobInstance, DBObject dbObject) {
195 | if (dbObject == null) {
196 | return null;
197 | }
198 | Long id = (Long) dbObject.get(JOB_EXECUTION_ID_KEY);
199 | JobExecution jobExecution;
200 |
201 | if (jobInstance == null) {
202 | jobExecution = new JobExecution(id);
203 | } else {
204 | jobExecution = new JobExecution(jobInstance, id);
205 | }
206 | jobExecution.setStartTime((Date) dbObject.get(START_TIME_KEY));
207 | jobExecution.setEndTime((Date) dbObject.get(END_TIME_KEY));
208 | jobExecution.setStatus(BatchStatus.valueOf((String) dbObject.get(STATUS_KEY)));
209 | jobExecution.setExitStatus(new ExitStatus(((String) dbObject.get(EXIT_CODE_KEY)), (String) dbObject.get(EXIT_MESSAGE_KEY)));
210 | jobExecution.setCreateTime((Date) dbObject.get(CREATE_TIME_KEY));
211 | jobExecution.setLastUpdated((Date) dbObject.get(LAST_UPDATED_KEY));
212 | jobExecution.setVersion((Integer) dbObject.get(VERSION_KEY));
213 | return jobExecution;
214 | }
215 |
216 |
217 | }
218 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/dao/MongoJobInstanceDao.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.BasicDBObject;
4 | import com.mongodb.DBCollection;
5 | import com.mongodb.DBCursor;
6 | import com.mongodb.DBObject;
7 | import org.springframework.batch.core.JobExecution;
8 | import org.springframework.batch.core.JobInstance;
9 | import org.springframework.batch.core.JobParameter;
10 | import org.springframework.batch.core.JobParameters;
11 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
12 | import org.springframework.stereotype.Repository;
13 | import org.springframework.util.Assert;
14 |
15 | import javax.annotation.PostConstruct;
16 | import java.io.UnsupportedEncodingException;
17 | import java.math.BigInteger;
18 | import java.security.MessageDigest;
19 | import java.security.NoSuchAlgorithmException;
20 | import java.util.*;
21 |
22 | import static com.mongodb.BasicDBObjectBuilder.start;
23 |
24 | /**
25 | * Created by IntelliJ IDEA.
26 | *
27 | * @author Baruch S.
28 | * @since Apr 15, 2010
29 | */
30 | @Repository
31 | public class MongoJobInstanceDao extends AbstractMongoDao implements JobInstanceDao {
32 |
33 | public static final String JOB_NAME_KEY = "jobName";
34 | static final String JOB_INSTANCE_ID_KEY = "jobInstanceId";
35 | protected static final String JOB_KEY_KEY = "jobKey";
36 | protected static final String JOB_PARAMETERS_KEY = "jobParameters";
37 |
38 | @PostConstruct
39 | public void init() {
40 | getCollection().ensureIndex(jobInstanceIdObj(1L));
41 | }
42 |
43 | public JobInstance createJobInstance(String jobName, final JobParameters jobParameters) {
44 | Assert.notNull(jobName, "Job name must not be null.");
45 | Assert.notNull(jobParameters, "JobParameters must not be null.");
46 |
47 | Assert.state(getJobInstance(jobName, jobParameters) == null,
48 | "JobInstance must not already exist");
49 |
50 | Long jobId = getNextId(JobInstance.class.getSimpleName());
51 |
52 | JobInstance jobInstance = new JobInstance(jobId, jobParameters, jobName);
53 |
54 | jobInstance.incrementVersion();
55 |
56 | Map jobParams = jobParameters.getParameters();
57 | Map paramMap = new HashMap(jobParams.size());
58 | for (Map.Entry entry : jobParams.entrySet()) {
59 | paramMap.put(entry.getKey().replaceAll(DOT_STRING, DOT_ESCAPE_STRING), entry.getValue().getValue());
60 | }
61 | getCollection().save(start()
62 | .add(JOB_INSTANCE_ID_KEY, jobId)
63 | .add(JOB_NAME_KEY, jobName)
64 | .add(JOB_KEY_KEY, createJobKey(jobParameters))
65 | .add(VERSION_KEY, jobInstance.getVersion())
66 | .add(JOB_PARAMETERS_KEY, new BasicDBObject(paramMap)).get());
67 | return jobInstance;
68 | }
69 |
70 | public JobInstance getJobInstance(String jobName, JobParameters jobParameters) {
71 | Assert.notNull(jobName, "Job name must not be null.");
72 | Assert.notNull(jobParameters, "JobParameters must not be null.");
73 |
74 | String jobKey = createJobKey(jobParameters);
75 |
76 | return mapJobInstance(getCollection().findOne(start()
77 | .add(JOB_NAME_KEY, jobName)
78 | .add(JOB_KEY_KEY, jobKey).get()), jobParameters);
79 | }
80 |
81 | public JobInstance getJobInstance(Long instanceId) {
82 | return mapJobInstance(getCollection().findOne(jobInstanceIdObj(instanceId)));
83 | }
84 |
85 | public JobInstance getJobInstance(JobExecution jobExecution) {
86 | DBObject instanceId = db.getCollection(JobExecution.class.getSimpleName()).findOne(MongoJobExecutionDao.jobExecutionIdObj(jobExecution.getId()), jobInstanceIdObj(1L));
87 | removeSystemFields(instanceId);
88 | return mapJobInstance(getCollection().findOne(instanceId));
89 | }
90 |
91 | public List getJobInstances(String jobName, int start, int count) {
92 | return mapJobInstances(getCollection().find(new BasicDBObject(JOB_NAME_KEY, jobName)).sort(jobInstanceIdObj(-1L)).skip(start).limit(count));
93 | }
94 |
95 | @SuppressWarnings({"unchecked"})
96 | public List getJobNames() {
97 | List results = getCollection().distinct(JOB_NAME_KEY);
98 | Collections.sort(results);
99 | return results;
100 | }
101 |
102 | protected String createJobKey(JobParameters jobParameters) {
103 |
104 | Map props = jobParameters.getParameters();
105 | StringBuilder stringBuilder = new StringBuilder();
106 | List keys = new ArrayList(props.keySet());
107 | Collections.sort(keys);
108 | for (String key : keys) {
109 | stringBuilder.append(key).append("=").append(props.get(key).toString()).append(";");
110 | }
111 |
112 | MessageDigest digest;
113 | try {
114 | digest = MessageDigest.getInstance("MD5");
115 | } catch (NoSuchAlgorithmException e) {
116 | throw new IllegalStateException(
117 | "MD5 algorithm not available. Fatal (should be in the JDK).");
118 | }
119 |
120 | try {
121 | byte[] bytes = digest.digest(stringBuilder.toString().getBytes(
122 | "UTF-8"));
123 | return String.format("%032x", new BigInteger(1, bytes));
124 | } catch (UnsupportedEncodingException e) {
125 | throw new IllegalStateException(
126 | "UTF-8 encoding not available. Fatal (should be in the JDK).");
127 | }
128 | }
129 |
130 | @Override
131 | protected DBCollection getCollection() {
132 | return db.getCollection(JobInstance.class.getSimpleName());
133 | }
134 |
135 | private List mapJobInstances(DBCursor dbCursor) {
136 | List results = new ArrayList();
137 | while (dbCursor.hasNext()) {
138 | results.add(mapJobInstance(dbCursor.next()));
139 | }
140 | return results;
141 | }
142 |
143 | private JobInstance mapJobInstance(DBObject dbObject) {
144 | return mapJobInstance(dbObject, null);
145 | }
146 |
147 | private JobInstance mapJobInstance(DBObject dbObject, JobParameters jobParameters) {
148 | JobInstance jobInstance = null;
149 | if (dbObject != null) {
150 | Long id = (Long) dbObject.get(JOB_INSTANCE_ID_KEY);
151 | if (jobParameters == null) {
152 | jobParameters = getJobParameters(id);
153 | }
154 | jobInstance = new JobInstance(id, jobParameters, (String) dbObject.get(JOB_NAME_KEY)); // should always be at version=0 because they never get updated
155 | jobInstance.incrementVersion();
156 | }
157 | return jobInstance;
158 | }
159 |
160 | @SuppressWarnings({"unchecked"})
161 | private JobParameters getJobParameters(Long jobInstanceId) {
162 | final Map jobParamsMap = (Map) getCollection().findOne(new BasicDBObject(jobInstanceIdObj(jobInstanceId))).get(JOB_PARAMETERS_KEY);
163 |
164 | Map map = new HashMap(jobParamsMap.size());
165 | for (Map.Entry entry : jobParamsMap.entrySet()) {
166 | Object param = entry.getValue();
167 | String key = entry.getKey().replaceAll(DOT_ESCAPE_STRING, DOT_STRING);
168 | if (param instanceof String) {
169 | map.put(key, new JobParameter((String) param));
170 | } else if (param instanceof Long) {
171 | map.put(key, new JobParameter((Long) param));
172 | } else if (param instanceof Double) {
173 | map.put(key, new JobParameter((Double) param));
174 | } else if (param instanceof Date) {
175 | map.put(key, new JobParameter((Date) param));
176 | } else {
177 | map.put(key, null);
178 | }
179 | }
180 | return new JobParameters(map);
181 | }
182 |
183 | static BasicDBObject jobInstanceIdObj(Long id) {
184 | return new BasicDBObject(MongoJobInstanceDao.JOB_INSTANCE_ID_KEY, id);
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/batch/mongo/dao/MongoStepExecutionDao.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.*;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.batch.core.BatchStatus;
7 | import org.springframework.batch.core.ExitStatus;
8 | import org.springframework.batch.core.JobExecution;
9 | import org.springframework.batch.core.StepExecution;
10 | import org.springframework.batch.core.repository.dao.StepExecutionDao;
11 | import org.springframework.dao.OptimisticLockingFailureException;
12 | import org.springframework.stereotype.Repository;
13 | import org.springframework.util.Assert;
14 |
15 | import javax.annotation.PostConstruct;
16 | import java.util.Date;
17 |
18 | import static com.mongodb.BasicDBObjectBuilder.start;
19 | import static org.springframework.batch.mongo.dao.MongoJobExecutionDao.JOB_EXECUTION_ID_KEY;
20 | import static org.springframework.batch.mongo.dao.MongoJobExecutionDao.jobExecutionIdObj;
21 | import static org.springframework.util.Assert.notNull;
22 |
23 | /**
24 | * Created by IntelliJ IDEA.
25 | *
26 | * @author Baruch S.
27 | * @since Apr 15, 2010
28 | */
29 | @Repository
30 | public class MongoStepExecutionDao extends AbstractMongoDao implements StepExecutionDao {
31 | protected static final String STEP_EXECUTION_ID_KEY = "stepExecutionId";
32 | public static final String STEP_NAME_KEY = "stepName";
33 | public static final String COMMIT_COUNT_KEY = "commitCount";
34 | public static final String READ_COUNT_KEY = "readCount";
35 | public static final String FILTER_COUT_KEY = "filterCout";
36 | public static final String WRITE_COUNT_KEY = "writeCount";
37 | protected static final String READ_SKIP_COUNT_KEY = "readSkipCount";
38 | protected static final String WRITE_SKIP_COUNT_KEY = "writeSkipCount";
39 | protected static final String PROCESS_SKIP_COUT_KEY = "processSkipCout";
40 | protected static final String ROLLBACK_COUNT_KEY = "rollbackCount";
41 | private static final Logger LOG = LoggerFactory.getLogger(MongoStepExecutionDao.class);
42 |
43 | @PostConstruct
44 | public void init() {
45 | getCollection().ensureIndex(BasicDBObjectBuilder.start().add(STEP_EXECUTION_ID_KEY, 1).add(JOB_EXECUTION_ID_KEY, 1).get());
46 |
47 | }
48 |
49 | public void saveStepExecution(StepExecution stepExecution) {
50 | Assert.isNull(stepExecution.getId(),
51 | "to-be-saved (not updated) StepExecution can't already have an id assigned");
52 | Assert.isNull(stepExecution.getVersion(),
53 | "to-be-saved (not updated) StepExecution can't already have a version assigned");
54 |
55 | validateStepExecution(stepExecution);
56 |
57 | stepExecution.setId(getNextId(StepExecution.class.getSimpleName()));
58 | stepExecution.incrementVersion(); // should be 0 now
59 | DBObject object = toDbObjectWithoutVersion(stepExecution);
60 | object.put(VERSION_KEY, stepExecution.getVersion());
61 | getCollection().save(object);
62 |
63 | }
64 |
65 | private DBObject toDbObjectWithoutVersion(StepExecution stepExecution) {
66 | return start()
67 | .add(STEP_EXECUTION_ID_KEY, stepExecution.getId())
68 | .add(STEP_NAME_KEY, stepExecution.getStepName())
69 | .add(JOB_EXECUTION_ID_KEY, stepExecution.getJobExecutionId())
70 | .add(START_TIME_KEY, stepExecution.getStartTime())
71 | .add(END_TIME_KEY, stepExecution.getEndTime())
72 | .add(STATUS_KEY, stepExecution.getStatus().toString())
73 | .add(COMMIT_COUNT_KEY, stepExecution.getCommitCount())
74 | .add(READ_COUNT_KEY, stepExecution.getReadCount())
75 | .add(FILTER_COUT_KEY, stepExecution.getFilterCount())
76 | .add(WRITE_COUNT_KEY, stepExecution.getWriteCount())
77 | .add(EXIT_CODE_KEY, stepExecution.getExitStatus().getExitCode())
78 | .add(EXIT_MESSAGE_KEY, stepExecution.getExitStatus().getExitDescription())
79 | .add(READ_SKIP_COUNT_KEY, stepExecution.getReadSkipCount())
80 | .add(WRITE_SKIP_COUNT_KEY, stepExecution.getWriteSkipCount())
81 | .add(PROCESS_SKIP_COUT_KEY, stepExecution.getProcessSkipCount())
82 | .add(ROLLBACK_COUNT_KEY, stepExecution.getRollbackCount())
83 | .add(LAST_UPDATED_KEY, stepExecution.getLastUpdated()).get();
84 | }
85 |
86 | public synchronized void updateStepExecution(StepExecution stepExecution) {
87 | // Attempt to prevent concurrent modification errors by blocking here if
88 | // someone is already trying to do it.
89 | Integer currentVersion = stepExecution.getVersion();
90 | Integer newVersion = currentVersion + 1;
91 | DBObject object = toDbObjectWithoutVersion(stepExecution);
92 | object.put(VERSION_KEY, newVersion);
93 | getCollection().update(start()
94 | .add(STEP_EXECUTION_ID_KEY, stepExecution.getId())
95 | .add(VERSION_KEY, currentVersion).get(),
96 | object);
97 |
98 | // Avoid concurrent modifications...
99 | DBObject lastError = db.getLastError();
100 | if (!((Boolean) lastError.get(UPDATED_EXISTING_STATUS))) {
101 | LOG.error("Update returned status {}", lastError);
102 | DBObject existingStepExecution = getCollection().findOne(stepExecutionIdObj(stepExecution.getId()), new BasicDBObject(VERSION_KEY, 1));
103 | if (existingStepExecution == null) {
104 | throw new IllegalArgumentException("Can't update this stepExecution, it was never saved.");
105 | }
106 | Integer curentVersion = ((Integer) existingStepExecution.get(VERSION_KEY));
107 | throw new OptimisticLockingFailureException("Attempt to update job execution id="
108 | + stepExecution.getId() + " with wrong version (" + currentVersion
109 | + "), where current version is " + curentVersion);
110 | }
111 |
112 | stepExecution.incrementVersion();
113 | }
114 |
115 |
116 | static BasicDBObject stepExecutionIdObj(Long id) {
117 | return new BasicDBObject(STEP_EXECUTION_ID_KEY, id);
118 | }
119 |
120 |
121 | public StepExecution getStepExecution(JobExecution jobExecution, Long stepExecutionId) {
122 | return mapStepExecution(getCollection().findOne(BasicDBObjectBuilder.start()
123 | .add(STEP_EXECUTION_ID_KEY, stepExecutionId)
124 | .add(JOB_EXECUTION_ID_KEY, jobExecution.getId()).get()), jobExecution);
125 | }
126 |
127 | private StepExecution mapStepExecution(DBObject object, JobExecution jobExecution) {
128 | if (object == null) {
129 | return null;
130 | }
131 | StepExecution stepExecution = new StepExecution((String) object.get(STEP_NAME_KEY), jobExecution, ((Long) object.get(STEP_EXECUTION_ID_KEY)));
132 | stepExecution.setStartTime((Date) object.get(START_TIME_KEY));
133 | stepExecution.setEndTime((Date) object.get(END_TIME_KEY));
134 | stepExecution.setStatus(BatchStatus.valueOf((String) object.get(STATUS_KEY)));
135 | stepExecution.setCommitCount((Integer) object.get(COMMIT_COUNT_KEY));
136 | stepExecution.setReadCount((Integer) object.get(READ_COUNT_KEY));
137 | stepExecution.setFilterCount((Integer) object.get(FILTER_COUT_KEY));
138 | stepExecution.setWriteCount((Integer) object.get(WRITE_COUNT_KEY));
139 | stepExecution.setExitStatus(new ExitStatus((String) object.get(EXIT_CODE_KEY), ((String) object.get(EXIT_MESSAGE_KEY))));
140 | stepExecution.setReadSkipCount((Integer) object.get(READ_SKIP_COUNT_KEY));
141 | stepExecution.setWriteSkipCount((Integer) object.get(WRITE_SKIP_COUNT_KEY));
142 | stepExecution.setProcessSkipCount((Integer) object.get(PROCESS_SKIP_COUT_KEY));
143 | stepExecution.setRollbackCount((Integer) object.get(ROLLBACK_COUNT_KEY));
144 | stepExecution.setLastUpdated((Date) object.get(LAST_UPDATED_KEY));
145 | stepExecution.setVersion((Integer) object.get(VERSION_KEY));
146 | return stepExecution;
147 |
148 | }
149 |
150 | public void addStepExecutions(JobExecution jobExecution) {
151 | DBCursor stepsCoursor = getCollection().find(jobExecutionIdObj(jobExecution.getId())).sort(stepExecutionIdObj(1L));
152 | while (stepsCoursor.hasNext()) {
153 | DBObject stepObject = stepsCoursor.next();
154 | //Calls constructor of StepExecution, which adds the step; Wow, that's unclear code!
155 | mapStepExecution(stepObject, jobExecution);
156 | }
157 | }
158 |
159 | @Override
160 | protected DBCollection getCollection() {
161 | return db.getCollection(StepExecution.class.getSimpleName());
162 | }
163 |
164 | private void validateStepExecution(StepExecution stepExecution) {
165 | notNull(stepExecution);
166 | notNull(stepExecution.getStepName(), "StepExecution step name cannot be null.");
167 | notNull(stepExecution.getStartTime(), "StepExecution start time cannot be null.");
168 | notNull(stepExecution.getStatus(), "StepExecution status cannot be null.");
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/javaconfig/util/ConfigurationSupport.java:
--------------------------------------------------------------------------------
1 | package org.springframework.javaconfig.util;
2 |
3 | import org.springframework.beans.factory.FactoryBean;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
6 | import org.springframework.context.*;
7 | import org.springframework.stereotype.Component;
8 |
9 |
10 | /**
11 | * Created by IntelliJ IDEA.
12 | *
13 | * @author Baruch S.
14 | * @since Apr 14, 2010
15 | */
16 | @Component
17 | public class ConfigurationSupport {
18 |
19 | @Autowired
20 | private AutowireCapableBeanFactory autowireCapableBeanFactory;
21 |
22 | @Autowired
23 | private ApplicationContext applicationContext;
24 |
25 | /**
26 | * Return the object created by this FactoryBean instance, first invoking
27 | * any container callbacks on the instance
28 | *
29 | * @param fb FactoryBean instance
30 | * @return the object created by the configured FactoryBean instance
31 | */
32 | @SuppressWarnings({"unchecked"})
33 | public T getObject(FactoryBean fb) {
34 | try {
35 |
36 | FactoryBean factoryBean = (FactoryBean) getConfigured(fb);
37 | return (T) factoryBean.getObject();
38 | }
39 | catch (Exception ex) {
40 | // TODO clean up
41 | throw new RuntimeException(ex);
42 | }
43 | }
44 |
45 | /* Invoke callbacks on the object, as though it was configured in the
46 | * factory
47 | * @param o object to configure
48 | * @return object after callbacks have been called on it
49 | */
50 |
51 | private Object getConfigured(Object o) {
52 | if (this.autowireCapableBeanFactory == null) {
53 | throw new UnsupportedOperationException(
54 | "Cannot configure object - not running in an AutowireCapableBeanFactory");
55 | }
56 |
57 | autowireCapableBeanFactory.initializeBean(o, null);
58 |
59 | // TODO could replace with ApplicationContextAwareProcessor call if that class were public
60 | if (this.applicationContext != null) {
61 | if (o instanceof ResourceLoaderAware) {
62 | ((ResourceLoaderAware) o).setResourceLoader(this.applicationContext);
63 | }
64 | if (o instanceof ApplicationEventPublisherAware) {
65 | ((ApplicationEventPublisherAware) o).setApplicationEventPublisher(this.applicationContext);
66 | }
67 | if (o instanceof MessageSourceAware) {
68 | ((MessageSourceAware) o).setMessageSource(this.applicationContext);
69 | }
70 | if (o instanceof ApplicationContextAware) {
71 | ((ApplicationContextAware) o).setApplicationContext(this.applicationContext);
72 | }
73 | }
74 |
75 | return o;
76 | }
77 |
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/resources/application-config.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/main/resources/batch.properties:
--------------------------------------------------------------------------------
1 | app.db.name=app
2 | batch.db.name=batch
3 | batch.start.limit=100
4 | batch.commit.interval=1
5 | step.thread.max.pool.size=10
6 | step.thread.core.pool.size=2
--------------------------------------------------------------------------------
/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
6 |
7 | INFO
8 |
9 |
10 |
11 |
12 |
13 | springbatch-over-mongodb.log
14 |
15 | logFile.%d{yyyy-MM-dd}.log
16 |
17 |
18 |
19 | %-4relative [%thread] %-5level %logger{35} - %msg%n
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/config/ApplicationTestConfiguration.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.config;
2 |
3 | import org.springframework.batch.test.JobLauncherTestUtils;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | /**
8 | * Created by IntelliJ IDEA.
9 | *
10 | * @author JBaruch
11 | * @since 19-Apr-2010
12 | */
13 | @Configuration
14 | public class ApplicationTestConfiguration {
15 |
16 | @Bean
17 | public JobLauncherTestUtils jobLauncherTestUtils() {
18 | return new JobLauncherTestUtils();
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/config/JobConfiguration.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.config;
2 |
3 | import org.springframework.batch.core.JobParametersIncrementer;
4 | import org.springframework.batch.core.Step;
5 | import org.springframework.batch.core.job.AbstractJob;
6 | import org.springframework.batch.core.job.SimpleJob;
7 | import org.springframework.batch.core.repository.JobRepository;
8 | import org.springframework.batch.core.step.item.SimpleStepFactoryBean;
9 | import org.springframework.batch.item.ItemReader;
10 | import org.springframework.batch.item.ItemWriter;
11 | import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.beans.factory.annotation.Value;
14 | import org.springframework.context.annotation.Bean;
15 | import org.springframework.context.annotation.Configuration;
16 | import org.springframework.core.task.TaskExecutor;
17 | import org.springframework.javaconfig.util.ConfigurationSupport;
18 |
19 | import java.util.Arrays;
20 |
21 | /**
22 | * Created by IntelliJ IDEA.
23 | *
24 | * @author JBaruch
25 | * @since 19-Apr-2010
26 | */
27 | @Configuration
28 | public class JobConfiguration {
29 |
30 | @Value("${batch.start.limit}")
31 | private int startLimit;
32 |
33 | @Value("${batch.commit.interval}")
34 | private int commitInterval;
35 |
36 |
37 | @Autowired
38 | private JobRepository jobRepository;
39 |
40 | @Autowired
41 | private ItemReader extends String> itemReader;
42 |
43 | @Autowired
44 | private ItemWriter super Object> itemWriter;
45 |
46 | @Autowired
47 | private TaskExecutor taskExecutor;
48 |
49 | @Autowired
50 | private ConfigurationSupport configurationSupport;
51 |
52 | @Autowired
53 | private JobParametersIncrementer jobParametersIncrementer;
54 |
55 | @Bean
56 | public Step step() {
57 | SimpleStepFactoryBean stepFactoryBean = new SimpleStepFactoryBean();
58 | stepFactoryBean.setTransactionManager(new ResourcelessTransactionManager());
59 | stepFactoryBean.setJobRepository(jobRepository);
60 | stepFactoryBean.setStartLimit(startLimit);
61 | stepFactoryBean.setCommitInterval(commitInterval);
62 | stepFactoryBean.setItemReader(itemReader);
63 | stepFactoryBean.setItemWriter(itemWriter);
64 | stepFactoryBean.setTaskExecutor(taskExecutor);
65 | return configurationSupport.getObject(stepFactoryBean);
66 | }
67 |
68 |
69 | @Bean
70 | public AbstractJob job() {
71 | SimpleJob job = new SimpleJob();
72 | job.setJobParametersIncrementer(jobParametersIncrementer);
73 | job.setJobRepository(jobRepository);
74 | job.setSteps(Arrays.asList(step()));
75 | return job;
76 | }
77 |
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/AbstractExecutionContextDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.DB;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.springframework.batch.core.JobExecution;
7 | import org.springframework.batch.core.JobInstance;
8 | import org.springframework.batch.core.JobParameters;
9 | import org.springframework.batch.core.StepExecution;
10 | import org.springframework.batch.core.repository.dao.ExecutionContextDao;
11 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
12 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
13 | import org.springframework.batch.core.repository.dao.StepExecutionDao;
14 | import org.springframework.batch.item.ExecutionContext;
15 | import org.springframework.batch.mongo.config.Database;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.transaction.annotation.Transactional;
18 |
19 | import java.util.Collections;
20 |
21 | import static org.junit.Assert.assertEquals;
22 |
23 | /**
24 | * Tests for {@link ExecutionContextDao} implementations.
25 | */
26 | @SuppressWarnings({"FieldCanBeLocal"})
27 | public abstract class AbstractExecutionContextDaoTests {
28 |
29 | private JobInstanceDao jobInstanceDao;
30 |
31 | private JobExecutionDao jobExecutionDao;
32 |
33 | private StepExecutionDao stepExecutionDao;
34 |
35 | private ExecutionContextDao contextDao;
36 |
37 | private JobExecution jobExecution;
38 |
39 | private StepExecution stepExecution;
40 |
41 | @Autowired
42 | @Database(Database.Purpose.BATCH)
43 | protected DB db;
44 |
45 | @Before
46 | public void setUp() {
47 | db.dropDatabase();
48 | jobInstanceDao = getJobInstanceDao();
49 | jobExecutionDao = getJobExecutionDao();
50 | stepExecutionDao = getStepExecutionDao();
51 | contextDao = getExecutionContextDao();
52 |
53 | JobInstance ji = jobInstanceDao.createJobInstance("testJob", new JobParameters());
54 | jobExecution = new JobExecution(ji);
55 | jobExecutionDao.saveJobExecution(jobExecution);
56 | stepExecution = new StepExecution("stepName", jobExecution);
57 | stepExecutionDao.saveStepExecution(stepExecution);
58 |
59 |
60 | }
61 |
62 | /**
63 | * @return Configured {@link ExecutionContextDao} implementation ready for
64 | * use.
65 | */
66 | protected abstract JobExecutionDao getJobExecutionDao();
67 |
68 | /**
69 | * @return Configured {@link ExecutionContextDao} implementation ready for
70 | * use.
71 | */
72 | protected abstract JobInstanceDao getJobInstanceDao();
73 |
74 | /**
75 | * @return Configured {@link ExecutionContextDao} implementation ready for
76 | * use.
77 | */
78 | protected abstract StepExecutionDao getStepExecutionDao();
79 |
80 | /**
81 | * @return Configured {@link ExecutionContextDao} implementation ready for
82 | * use.
83 | */
84 | protected abstract ExecutionContextDao getExecutionContextDao();
85 |
86 | @Transactional
87 | @Test
88 | public void testSaveAndFindJobContext() {
89 |
90 | ExecutionContext ctx = new ExecutionContext(Collections.singletonMap("key", "value"));
91 | jobExecution.setExecutionContext(ctx);
92 | contextDao.saveExecutionContext(jobExecution);
93 |
94 | ExecutionContext retrieved = contextDao.getExecutionContext(jobExecution);
95 | assertEquals(ctx, retrieved);
96 | }
97 |
98 | @Transactional
99 | @Test
100 | public void testSaveAndFindEmptyJobContext() {
101 |
102 | ExecutionContext ctx = new ExecutionContext();
103 | jobExecution.setExecutionContext(ctx);
104 | contextDao.saveExecutionContext(jobExecution);
105 |
106 | ExecutionContext retrieved = contextDao.getExecutionContext(jobExecution);
107 | assertEquals(ctx, retrieved);
108 | }
109 |
110 | @Transactional
111 | @Test
112 | public void testUpdateContext() {
113 |
114 | ExecutionContext ctx = new ExecutionContext(Collections
115 | .singletonMap("key", "value"));
116 | jobExecution.setExecutionContext(ctx);
117 | contextDao.saveExecutionContext(jobExecution);
118 |
119 | ctx.putLong("longKey", 7);
120 | contextDao.updateExecutionContext(jobExecution);
121 |
122 | ExecutionContext retrieved = contextDao.getExecutionContext(jobExecution);
123 | assertEquals(ctx, retrieved);
124 | assertEquals(7, retrieved.getLong("longKey"));
125 | }
126 |
127 | @Transactional
128 | @Test
129 | public void testSaveAndFindStepContext() {
130 |
131 | ExecutionContext ctx = new ExecutionContext(Collections.singletonMap("key", "value"));
132 | stepExecution.setExecutionContext(ctx);
133 | contextDao.saveExecutionContext(stepExecution);
134 |
135 | ExecutionContext retrieved = contextDao.getExecutionContext(stepExecution);
136 | assertEquals(ctx, retrieved);
137 | }
138 |
139 | @Transactional
140 | @Test
141 | public void testSaveAndFindEmptyStepContext() {
142 |
143 | ExecutionContext ctx = new ExecutionContext();
144 | stepExecution.setExecutionContext(ctx);
145 | contextDao.saveExecutionContext(stepExecution);
146 |
147 | ExecutionContext retrieved = contextDao.getExecutionContext(stepExecution);
148 | assertEquals(ctx, retrieved);
149 | }
150 |
151 | @Transactional
152 | @Test
153 | public void testUpdateStepContext() {
154 |
155 | ExecutionContext ctx = new ExecutionContext(Collections.singletonMap("key", "value"));
156 | stepExecution.setExecutionContext(ctx);
157 | contextDao.saveExecutionContext(stepExecution);
158 |
159 | ctx.putLong("longKey", 7);
160 | contextDao.updateExecutionContext(stepExecution);
161 |
162 | ExecutionContext retrieved = contextDao.getExecutionContext(stepExecution);
163 | assertEquals(ctx, retrieved);
164 | assertEquals(7, retrieved.getLong("longKey"));
165 | }
166 |
167 | @Transactional
168 | @Test
169 | public void testStoreInteger() {
170 |
171 | ExecutionContext ec = new ExecutionContext();
172 | ec.put("intValue", 343232);
173 | stepExecution.setExecutionContext(ec);
174 | contextDao.saveExecutionContext(stepExecution);
175 | ExecutionContext restoredEc = contextDao.getExecutionContext(stepExecution);
176 | assertEquals(ec, restoredEc);
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/AbstractJobDaoTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2007 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.batch.mongo.dao;
18 |
19 | import com.mongodb.BasicDBObject;
20 | import com.mongodb.DB;
21 | import com.mongodb.DBObject;
22 | import org.junit.Before;
23 | import org.junit.Test;
24 | import org.springframework.batch.core.*;
25 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
26 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
27 | import org.springframework.batch.core.repository.dao.NoSuchObjectException;
28 | import org.springframework.batch.mongo.config.Database;
29 | import org.springframework.beans.factory.annotation.Autowired;
30 | import org.springframework.transaction.annotation.Transactional;
31 |
32 | import java.util.Date;
33 | import java.util.List;
34 |
35 | import static org.junit.Assert.*;
36 | import static org.springframework.batch.mongo.dao.AbstractMongoDao.VERSION_KEY;
37 | import static org.springframework.batch.mongo.dao.MongoJobExecutionDao.JOB_EXECUTION_ID_KEY;
38 | import static org.springframework.batch.mongo.dao.MongoJobInstanceDao.JOB_INSTANCE_ID_KEY;
39 | import static org.springframework.batch.mongo.dao.MongoJobInstanceDao.JOB_NAME_KEY;
40 |
41 | /**
42 | * @author Dave Syer
43 | */
44 | public abstract class AbstractJobDaoTests {
45 |
46 | protected JobInstanceDao jobInstanceDao;
47 |
48 | protected JobExecutionDao jobExecutionDao;
49 |
50 | protected JobParameters jobParameters = new JobParametersBuilder().addString("job.key", "jobKey").addLong("long",
51 | (long) 1).addDate("date", new Date(7)).addDouble("double", 7.7).toJobParameters();
52 |
53 | protected JobInstance jobInstance;
54 |
55 | protected String jobName = "Job1";
56 |
57 | protected JobExecution jobExecution;
58 |
59 | protected Date jobExecutionStartTime = new Date(System.currentTimeMillis());
60 |
61 | @Autowired
62 | @Database(Database.Purpose.BATCH)
63 | protected DB db;
64 |
65 | /*
66 | * Because AbstractTransactionalSpringContextTests is used, this method will
67 | * be called by Spring to set the JobRepository.
68 | */
69 |
70 | @Autowired
71 | public void setJobInstanceDao(JobInstanceDao jobInstanceDao) {
72 | this.jobInstanceDao = jobInstanceDao;
73 | }
74 |
75 | @Autowired
76 | public void setJobExecutionDao(JobExecutionDao jobExecutionDao) {
77 | this.jobExecutionDao = jobExecutionDao;
78 | }
79 |
80 | @Before
81 | public void onSetUpInTransaction() throws Exception {
82 | db.dropDatabase();
83 | // Create job.
84 | jobInstance = jobInstanceDao.createJobInstance(jobName, jobParameters);
85 |
86 | // Create an execution
87 | jobExecutionStartTime = new Date(System.currentTimeMillis());
88 | jobExecution = new JobExecution(jobInstance);
89 | jobExecution.setStartTime(jobExecutionStartTime);
90 | jobExecution.setStatus(BatchStatus.STARTED);
91 | jobExecutionDao.saveJobExecution(jobExecution);
92 | }
93 |
94 | @Transactional
95 | @Test
96 | public void testVersionIsNotNullForJob() throws Exception {
97 | assertEquals(0, getVersion(JobInstance.class.getSimpleName(), jobInstance.getId(), JOB_INSTANCE_ID_KEY));
98 | }
99 |
100 | private int getVersion(String collectionName, Long id, String idKey) {
101 | DBObject dbObject = db.getCollection(collectionName).findOne(new BasicDBObject(idKey, id), new BasicDBObject(VERSION_KEY, 1));
102 | return dbObject == null ? 0 : (Integer) dbObject.get(VERSION_KEY);
103 | }
104 |
105 | @Transactional
106 | @Test
107 | public void testVersionIsNotNullForJobExecution() throws Exception {
108 | assertEquals(0, getVersion(JobExecution.class.getSimpleName(), jobExecution.getId(), JOB_EXECUTION_ID_KEY));
109 | }
110 |
111 | @Transactional
112 | @Test
113 | public void testFindNonExistentJob() {
114 | // No job should be found since it hasn't been created.
115 | JobInstance jobInstance = jobInstanceDao.getJobInstance("nonexistentJob", jobParameters);
116 | assertNull(jobInstance);
117 | }
118 |
119 | @Transactional
120 | @Test
121 | public void testFindJob() {
122 |
123 | JobInstance instance = jobInstanceDao.getJobInstance(jobName, jobParameters);
124 | assertNotNull(instance);
125 | assertTrue(jobInstance.equals(instance));
126 | assertEquals(jobParameters, instance.getJobParameters());
127 | }
128 |
129 | @Transactional
130 | @Test(expected = IllegalArgumentException.class)
131 | public void testFindJobWithNullRuntime() {
132 | jobInstanceDao.getJobInstance(null, null);
133 | }
134 |
135 | /**
136 | * Test that ensures that if you create a job with a given name, then find a
137 | * job with the same name, but other pieces of the identifier different, you
138 | * get no result, not the existing one.
139 | */
140 | @Transactional
141 | @Test
142 | public void testCreateJobWithExistingName() {
143 |
144 | String scheduledJob = "ScheduledJob";
145 | jobInstanceDao.createJobInstance(scheduledJob, jobParameters);
146 |
147 | // Modifying the key should bring back a completely different
148 | // JobInstance
149 | JobParameters tempProps = new JobParametersBuilder().addString("job.key", "testKey1").toJobParameters();
150 |
151 | JobInstance instance;
152 | instance = jobInstanceDao.getJobInstance(scheduledJob, jobParameters);
153 | assertNotNull(instance);
154 | assertEquals(jobParameters, instance.getJobParameters());
155 |
156 | instance = jobInstanceDao.getJobInstance(scheduledJob, tempProps);
157 | assertNull(instance);
158 |
159 | }
160 |
161 | @Transactional
162 | @Test
163 | public void testUpdateJobExecution() {
164 |
165 | jobExecution.setStatus(BatchStatus.COMPLETED);
166 | jobExecution.setExitStatus(ExitStatus.COMPLETED);
167 | jobExecution.setEndTime(new Date(System.currentTimeMillis()));
168 | jobExecutionDao.updateJobExecution(jobExecution);
169 |
170 | List executions = jobExecutionDao.findJobExecutions(jobInstance);
171 | assertEquals(executions.size(), 1);
172 | validateJobExecution(jobExecution, executions.get(0));
173 |
174 | }
175 |
176 | @Transactional
177 | @Test
178 | public void testSaveJobExecution() {
179 |
180 | List executions = jobExecutionDao.findJobExecutions(jobInstance);
181 | assertEquals(executions.size(), 1);
182 | validateJobExecution(jobExecution, executions.get(0));
183 | }
184 |
185 | @Transactional
186 | @Test(expected = NoSuchObjectException.class)
187 | public void testUpdateInvalidJobExecution() {
188 | // id is invalid
189 | JobExecution execution = new JobExecution(jobInstance, (long) 29432);
190 | execution.incrementVersion();
191 | jobExecutionDao.updateJobExecution(execution);
192 | }
193 |
194 | @Transactional
195 | @Test(expected = IllegalArgumentException.class)
196 | public void testUpdateNullIdJobExection() {
197 | JobExecution execution = new JobExecution(jobInstance);
198 | jobExecutionDao.updateJobExecution(execution);
199 | }
200 |
201 |
202 | @Transactional
203 | @Test
204 | public void testJobWithSimpleJobIdentifier() throws Exception {
205 |
206 | String testJob = "test";
207 | // Create job.
208 | jobInstance = jobInstanceDao.createJobInstance(testJob, jobParameters);
209 | DBObject dbObject = db.getCollection(JobInstance.class.getSimpleName()).findOne(new BasicDBObject(JOB_INSTANCE_ID_KEY, jobInstance.getId()));
210 | assertEquals("test", dbObject.get(JOB_NAME_KEY));
211 | }
212 |
213 | @Transactional
214 | @Test
215 | public void testJobWithDefaultJobIdentifier() throws Exception {
216 |
217 | String testDefaultJob = "testDefault";
218 | // Create job.
219 | jobInstance = jobInstanceDao.createJobInstance(testDefaultJob, jobParameters);
220 |
221 | JobInstance instance = jobInstanceDao.getJobInstance(testDefaultJob, jobParameters);
222 |
223 | assertNotNull(instance);
224 | assertEquals(jobParameters.getString("job.key"), instance.getJobParameters().getString(
225 | "job.key"));
226 |
227 | }
228 |
229 | @Transactional
230 | @Test
231 | public void testFindJobExecutions() {
232 |
233 | List results = jobExecutionDao.findJobExecutions(jobInstance);
234 | assertEquals(results.size(), 1);
235 | validateJobExecution(jobExecution, results.get(0));
236 | }
237 |
238 | @Transactional
239 | @Test
240 | public void testFindJobsWithProperties() throws Exception {
241 |
242 | }
243 |
244 | private void validateJobExecution(JobExecution lhs, JobExecution rhs) {
245 |
246 | // equals operator only checks id
247 | assertEquals(lhs, rhs);
248 | assertEquals(lhs.getStartTime(), rhs.getStartTime());
249 | assertEquals(lhs.getEndTime(), rhs.getEndTime());
250 | assertEquals(lhs.getStatus(), rhs.getStatus());
251 | assertEquals(lhs.getExitStatus(), rhs.getExitStatus());
252 | }
253 |
254 | @Transactional
255 | @Test
256 | public void testGetLastJobExecution() {
257 | JobExecution lastExecution = new JobExecution(jobInstance);
258 | lastExecution.setStatus(BatchStatus.STARTED);
259 |
260 | int JUMP_INTO_FUTURE = 1000; // makes sure start time is 'greatest'
261 | lastExecution.setCreateTime(new Date(System.currentTimeMillis() + JUMP_INTO_FUTURE));
262 | jobExecutionDao.saveJobExecution(lastExecution);
263 |
264 | assertEquals(lastExecution, jobExecutionDao.getLastJobExecution(jobInstance));
265 | }
266 |
267 | /**
268 | * Trying to create instance twice for the same job+parameters causes error
269 | */
270 | @Transactional
271 | @Test(expected = IllegalStateException.class)
272 | public void testCreateDuplicateInstance() {
273 | jobParameters = new JobParameters();
274 | jobInstanceDao.createJobInstance(jobName, jobParameters);
275 | jobInstanceDao.createJobInstance(jobName, jobParameters);
276 | }
277 |
278 | @Transactional
279 | @Test
280 | public void testCreationAddsVersion() {
281 | jobInstance = jobInstanceDao.createJobInstance("testCreationAddsVersion", new JobParameters());
282 | assertNotNull(jobInstance.getVersion());
283 | }
284 |
285 | @Transactional
286 | @Test
287 | public void testSaveAddsVersionAndId() {
288 |
289 | JobExecution jobExecution = new JobExecution(jobInstance);
290 |
291 | assertNull(jobExecution.getId());
292 | assertNull(jobExecution.getVersion());
293 |
294 | jobExecutionDao.saveJobExecution(jobExecution);
295 |
296 | assertNotNull(jobExecution.getId());
297 | assertNotNull(jobExecution.getVersion());
298 | }
299 |
300 | @Transactional
301 | @Test
302 | public void testUpdateIncrementsVersion() {
303 | int version = jobExecution.getVersion();
304 |
305 | jobExecutionDao.updateJobExecution(jobExecution);
306 |
307 | assertEquals(version + 1, jobExecution.getVersion().intValue());
308 | }
309 | }
310 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/AbstractJobExecutionDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.DB;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.springframework.batch.core.*;
7 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
8 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
9 | import org.springframework.batch.core.repository.dao.StepExecutionDao;
10 | import org.springframework.batch.mongo.config.Database;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.dao.OptimisticLockingFailureException;
13 | import org.springframework.transaction.annotation.Transactional;
14 | import org.springframework.util.Assert;
15 |
16 | import java.util.*;
17 |
18 | import static org.junit.Assert.*;
19 |
20 | public abstract class AbstractJobExecutionDaoTests {
21 |
22 | protected JobExecutionDao dao;
23 |
24 | protected JobInstance jobInstance;
25 |
26 | protected JobExecution execution;
27 |
28 | @Autowired
29 | @Database(Database.Purpose.BATCH)
30 | protected DB db;
31 |
32 | /**
33 | * @return tested object ready for use
34 | */
35 | protected abstract JobExecutionDao getJobExecutionDao();
36 |
37 | protected abstract JobInstanceDao getJobInstanceDao();
38 |
39 | /**
40 | * @return tested object ready for use
41 | */
42 | protected StepExecutionDao getStepExecutionDao() {
43 | return null;
44 | }
45 |
46 | @Before
47 | public void onSetUp() throws Exception {
48 | db.dropDatabase();
49 | dao = getJobExecutionDao();
50 | jobInstance = getJobInstanceDao().createJobInstance("execTestJob", new JobParameters());
51 | execution = new JobExecution(jobInstance);
52 | }
53 |
54 | /**
55 | * Save and find a job execution.
56 | */
57 | @Transactional
58 | @Test
59 | public void testSaveAndFind() {
60 |
61 | execution.setStartTime(new Date(System.currentTimeMillis()));
62 | execution.setLastUpdated(new Date(System.currentTimeMillis()));
63 | execution.setExitStatus(ExitStatus.UNKNOWN);
64 | execution.setEndTime(new Date(System.currentTimeMillis()));
65 | dao.saveJobExecution(execution);
66 |
67 | List executions = dao.findJobExecutions(jobInstance);
68 | assertEquals(1, executions.size());
69 | assertEquals(execution, executions.get(0));
70 | assertExecutionsAreEqual(execution, executions.get(0));
71 | }
72 |
73 | /**
74 | * Executions should be returned in the reverse order they were saved.
75 | */
76 | @Transactional
77 | @Test
78 | public void testFindExecutionsOrdering() {
79 |
80 | List execs = new ArrayList();
81 |
82 | for (int i = 0; i < 10; i++) {
83 | JobExecution exec = new JobExecution(jobInstance);
84 | exec.setCreateTime(new Date(i));
85 | execs.add(exec);
86 | dao.saveJobExecution(exec);
87 | }
88 |
89 | List retrieved = dao.findJobExecutions(jobInstance);
90 | Collections.reverse(retrieved);
91 |
92 | for (int i = 0; i < 10; i++) {
93 | assertExecutionsAreEqual(execs.get(i), retrieved.get(i));
94 | }
95 |
96 | }
97 |
98 | /**
99 | * Save and find a job execution.
100 | */
101 | @Transactional
102 | @Test
103 | public void testFindNonExistentExecutions() {
104 | List executions = dao.findJobExecutions(jobInstance);
105 | assertEquals(0, executions.size());
106 | }
107 |
108 | /**
109 | * Saving sets id to the entity.
110 | */
111 | @Transactional
112 | @Test
113 | public void testSaveAddsIdAndVersion() {
114 |
115 | assertNull(execution.getId());
116 | assertNull(execution.getVersion());
117 | dao.saveJobExecution(execution);
118 | assertNotNull(execution.getId());
119 | assertNotNull(execution.getVersion());
120 | }
121 |
122 | /**
123 | * Update and retrieve job execution - check attributes have changed as
124 | * expected.
125 | */
126 | @Transactional
127 | @Test
128 | public void testUpdateExecution() {
129 | execution.setStatus(BatchStatus.STARTED);
130 | dao.saveJobExecution(execution);
131 |
132 | execution.setLastUpdated(new Date(0));
133 | execution.setStatus(BatchStatus.COMPLETED);
134 | dao.updateJobExecution(execution);
135 |
136 | JobExecution updated = dao.findJobExecutions(jobInstance).get(0);
137 | assertEquals(execution, updated);
138 | assertEquals(BatchStatus.COMPLETED, updated.getStatus());
139 | assertExecutionsAreEqual(execution, updated);
140 | }
141 |
142 | /**
143 | * Check the execution with most recent start time is returned
144 | */
145 | @Transactional
146 | @Test
147 | public void testGetLastExecution() {
148 | JobExecution exec1 = new JobExecution(jobInstance);
149 | exec1.setCreateTime(new Date(0));
150 |
151 | JobExecution exec2 = new JobExecution(jobInstance);
152 | exec2.setCreateTime(new Date(1));
153 |
154 | dao.saveJobExecution(exec1);
155 | dao.saveJobExecution(exec2);
156 |
157 | JobExecution last = dao.getLastJobExecution(jobInstance);
158 | assertEquals(exec2, last);
159 | }
160 |
161 | /**
162 | * Check the execution is returned
163 | */
164 | @Transactional
165 | @Test
166 | public void testGetMissingLastExecution() {
167 | JobExecution value = dao.getLastJobExecution(jobInstance);
168 | assertNull(value);
169 | }
170 |
171 | /**
172 | * Check the execution is returned
173 | */
174 | @Transactional
175 | @Test
176 | public void testFindRunningExecutions() {
177 |
178 | JobExecution exec = new JobExecution(jobInstance);
179 | exec.setCreateTime(new Date(0));
180 | exec.setEndTime(new Date(1L));
181 | exec.setLastUpdated(new Date(5L));
182 | dao.saveJobExecution(exec);
183 |
184 | exec = new JobExecution(jobInstance);
185 | exec.setLastUpdated(new Date(5L));
186 | exec.createStepExecution("step");
187 | dao.saveJobExecution(exec);
188 |
189 | StepExecutionDao stepExecutionDao = getStepExecutionDao();
190 | if (stepExecutionDao != null) {
191 | for (StepExecution stepExecution : exec.getStepExecutions()) {
192 | stepExecutionDao.saveStepExecution(stepExecution);
193 | }
194 | }
195 |
196 | Set values = dao.findRunningJobExecutions(exec.getJobInstance().getJobName());
197 |
198 | assertEquals(1, values.size());
199 | JobExecution value = values.iterator().next();
200 | assertEquals(exec, value);
201 | assertEquals(5L, value.getLastUpdated().getTime());
202 |
203 | }
204 |
205 | /**
206 | * Check the execution is returned
207 | */
208 | @Transactional
209 | @Test
210 | public void testNoRunningExecutions() {
211 | Set values = dao.findRunningJobExecutions("no-such-job");
212 | assertEquals(0, values.size());
213 | }
214 |
215 | /**
216 | * Check the execution is returned
217 | */
218 | @Transactional
219 | @Test
220 | public void testGetExecution() {
221 | JobExecution exec = new JobExecution(jobInstance);
222 | exec.setCreateTime(new Date(0));
223 | exec.createStepExecution("step");
224 |
225 | dao.saveJobExecution(exec);
226 | StepExecutionDao stepExecutionDao = getStepExecutionDao();
227 | if (stepExecutionDao != null) {
228 | for (StepExecution stepExecution : exec.getStepExecutions()) {
229 | stepExecutionDao.saveStepExecution(stepExecution);
230 | }
231 | }
232 | JobExecution value = dao.getJobExecution(exec.getId());
233 |
234 | assertEquals(exec, value);
235 | // N.B. the job instance is not re-hydrated in the JDBC case...
236 | }
237 |
238 | /**
239 | * Check the execution is returned
240 | */
241 | @Transactional
242 | @Test
243 | public void testGetMissingExecution() {
244 | JobExecution value = dao.getJobExecution(54321L);
245 | assertNull(value);
246 | }
247 |
248 | /**
249 | * Exception should be raised when the version of update argument doesn't
250 | * match the version of persisted entity.
251 | */
252 | @Transactional
253 | @Test(expected = OptimisticLockingFailureException.class)
254 | public void testConcurrentModificationException() {
255 |
256 | JobExecution exec1 = new JobExecution(jobInstance);
257 | dao.saveJobExecution(exec1);
258 |
259 | JobExecution exec2 = new JobExecution(jobInstance);
260 | exec2.setId(exec1.getId());
261 |
262 | exec2.incrementVersion();
263 | assertEquals((Integer) 0, exec1.getVersion());
264 | assertEquals(exec1.getVersion(), exec2.getVersion());
265 |
266 | dao.updateJobExecution(exec1);
267 | assertEquals((Integer) 1, exec1.getVersion());
268 | dao.updateJobExecution(exec2);
269 | }
270 |
271 | /**
272 | * Successful synchronization from STARTED to STOPPING status.
273 | */
274 | @Transactional
275 | @Test
276 | public void testSynchronizeStatusUpgrade() {
277 |
278 | JobExecution exec1 = new JobExecution(jobInstance);
279 | exec1.setStatus(BatchStatus.STOPPING);
280 | dao.saveJobExecution(exec1);
281 |
282 | JobExecution exec2 = new JobExecution(jobInstance);
283 | Assert.state(exec1.getId() != null);
284 | exec2.setId(exec1.getId());
285 |
286 | exec2.setStatus(BatchStatus.STARTED);
287 | exec2.setVersion(7);
288 | Assert.state(!exec1.getVersion().equals(exec2.getVersion()));
289 | Assert.state(exec1.getStatus() != exec2.getStatus());
290 |
291 | dao.synchronizeStatus(exec2);
292 |
293 | assertEquals(exec1.getVersion(), exec2.getVersion());
294 | assertEquals(exec1.getStatus(), exec2.getStatus());
295 | }
296 |
297 | /**
298 | * UNKNOWN status won't be changed by synchronizeStatus, because it is the
299 | * 'largest' BatchStatus (will not downgrade).
300 | */
301 | @Transactional
302 | @Test
303 | public void testSynchronizeStatusDowngrade() {
304 |
305 | JobExecution exec1 = new JobExecution(jobInstance);
306 | exec1.setStatus(BatchStatus.STARTED);
307 | dao.saveJobExecution(exec1);
308 |
309 | JobExecution exec2 = new JobExecution(jobInstance);
310 | Assert.state(exec1.getId() != null);
311 | exec2.setId(exec1.getId());
312 |
313 | exec2.setStatus(BatchStatus.UNKNOWN);
314 | exec2.setVersion(7);
315 | Assert.state(!exec1.getVersion().equals(exec2.getVersion()));
316 | Assert.state(exec1.getStatus().isLessThan(exec2.getStatus()));
317 |
318 | dao.synchronizeStatus(exec2);
319 |
320 | assertEquals(exec1.getVersion(), exec2.getVersion());
321 | assertEquals(BatchStatus.UNKNOWN, exec2.getStatus());
322 | }
323 |
324 | /*
325 | * Check to make sure the executions are equal. Normally, comparing the id's
326 | * is sufficient. However, for testing purposes, especially of a DAO, we
327 | * need to make sure all the fields are being stored/retrieved correctly.
328 | */
329 |
330 | private void assertExecutionsAreEqual(JobExecution lhs, JobExecution rhs) {
331 |
332 | assertEquals(lhs.getId(), rhs.getId());
333 | assertEquals(lhs.getStartTime(), rhs.getStartTime());
334 | assertEquals(lhs.getStatus(), rhs.getStatus());
335 | assertEquals(lhs.getEndTime(), rhs.getEndTime());
336 | assertEquals(lhs.getCreateTime(), rhs.getCreateTime());
337 | assertEquals(lhs.getLastUpdated(), rhs.getLastUpdated());
338 | assertEquals(lhs.getVersion(), rhs.getVersion());
339 | }
340 |
341 | }
342 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/AbstractJobInstanceDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.DB;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.springframework.batch.core.JobInstance;
7 | import org.springframework.batch.core.JobParameters;
8 | import org.springframework.batch.core.JobParametersBuilder;
9 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
10 | import org.springframework.batch.mongo.config.Database;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.transaction.annotation.Transactional;
13 |
14 | import java.util.Date;
15 | import java.util.List;
16 |
17 | import static org.junit.Assert.*;
18 |
19 | public abstract class AbstractJobInstanceDaoTests {
20 |
21 | private static final long DATE = 777;
22 |
23 | protected JobInstanceDao dao;
24 |
25 | private String fooJob = "foo";
26 |
27 | private JobParameters fooParams = new JobParametersBuilder().addString("stringKey", "stringValue").addLong(
28 | "longKey", Long.MAX_VALUE).addDouble("doubleKey", Double.MAX_VALUE).addDate("dateKey", new Date(DATE))
29 | .toJobParameters();
30 |
31 | protected abstract JobInstanceDao getJobInstanceDao();
32 |
33 | @Autowired
34 | @Database(Database.Purpose.BATCH)
35 | protected DB db;
36 |
37 | @Before
38 | public void onSetUp() throws Exception {
39 | db.dropDatabase();
40 | dao = getJobInstanceDao();
41 | }
42 |
43 | /*
44 | * Create and retrieve a job instance.
45 | */
46 |
47 | @Transactional
48 | @Test
49 | public void testCreateAndRetrieve() throws Exception {
50 |
51 | JobInstance fooInstance = dao.createJobInstance(fooJob, fooParams);
52 | assertNotNull(fooInstance.getId());
53 | assertEquals(fooJob, fooInstance.getJobName());
54 | assertEquals(fooParams, fooInstance.getJobParameters());
55 |
56 | JobInstance retrievedInstance = dao.getJobInstance(fooJob, fooParams);
57 | JobParameters retrievedParams = retrievedInstance.getJobParameters();
58 | assertEquals(fooInstance, retrievedInstance);
59 | assertEquals(fooJob, retrievedInstance.getJobName());
60 | assertEquals(fooParams, retrievedParams);
61 |
62 | assertEquals(Long.MAX_VALUE, retrievedParams.getLong("longKey"));
63 | assertEquals(Double.MAX_VALUE, retrievedParams.getDouble("doubleKey"), 0.001);
64 | assertEquals("stringValue", retrievedParams.getString("stringKey"));
65 | assertEquals(new Date(DATE), retrievedParams.getDate("dateKey"));
66 | }
67 |
68 | /*
69 | * Create and retrieve a job instance.
70 | */
71 |
72 | @Transactional
73 | @Test
74 | public void testCreateAndGetById() throws Exception {
75 |
76 | JobInstance fooInstance = dao.createJobInstance(fooJob, fooParams);
77 | assertNotNull(fooInstance.getId());
78 | assertEquals(fooJob, fooInstance.getJobName());
79 | assertEquals(fooParams, fooInstance.getJobParameters());
80 |
81 | JobInstance retrievedInstance = dao.getJobInstance(fooInstance.getId());
82 | JobParameters retrievedParams = retrievedInstance.getJobParameters();
83 | assertEquals(fooInstance, retrievedInstance);
84 | assertEquals(fooJob, retrievedInstance.getJobName());
85 | assertEquals(fooParams, retrievedParams);
86 |
87 | assertEquals(Long.MAX_VALUE, retrievedParams.getLong("longKey"));
88 | assertEquals(Double.MAX_VALUE, retrievedParams.getDouble("doubleKey"), 0.001);
89 | assertEquals("stringValue", retrievedParams.getString("stringKey"));
90 | assertEquals(new Date(DATE), retrievedParams.getDate("dateKey"));
91 | }
92 |
93 | /*
94 | * Create and retrieve a job instance.
95 | */
96 |
97 | @Transactional
98 | @Test
99 | public void testGetMissingById() throws Exception {
100 |
101 | JobInstance retrievedInstance = dao.getJobInstance(1111111L);
102 | assertNull(retrievedInstance);
103 |
104 | }
105 |
106 | /*
107 | * Create and retrieve a job instance.
108 | */
109 |
110 | @Transactional
111 | @Test
112 | public void testGetJobNames() throws Exception {
113 |
114 | testCreateAndRetrieve();
115 | List jobNames = dao.getJobNames();
116 | assertFalse(jobNames.isEmpty());
117 | assertTrue(jobNames.contains(fooJob));
118 |
119 | }
120 |
121 | /**
122 | * Create and retrieve a job instance.
123 | *
124 | * @throws Exception when shit happens
125 | */
126 | @Transactional
127 | @Test
128 | public void testGetLastInstances() throws Exception {
129 |
130 | testCreateAndRetrieve();
131 |
132 | // unrelated job instance that should be ignored by the query
133 | dao.createJobInstance("anotherJob", new JobParameters());
134 |
135 | // we need two instances of the same job to check ordering
136 | dao.createJobInstance(fooJob, new JobParameters());
137 |
138 | List jobInstances = dao.getJobInstances(fooJob, 0, 2);
139 | assertEquals(2, jobInstances.size());
140 | assertEquals(fooJob, jobInstances.get(0).getJobName());
141 | assertEquals(fooJob, jobInstances.get(1).getJobName());
142 | assertEquals(Integer.valueOf(0), jobInstances.get(0).getVersion());
143 | assertEquals(Integer.valueOf(0), jobInstances.get(1).getVersion());
144 |
145 | assertTrue("Last instance should be first on the list", jobInstances.get(0).getId() > jobInstances.get(1).getId());
146 |
147 | }
148 |
149 | /**
150 | * Create and retrieve a job instance.
151 | *
152 | * @throws Exception when shit happens
153 | */
154 | @Transactional
155 | @Test
156 | public void testGetLastInstancesPaged() throws Exception {
157 |
158 | testCreateAndRetrieve();
159 |
160 | // unrelated job instance that should be ignored by the query
161 | dao.createJobInstance("anotherJob", new JobParameters());
162 |
163 | // we need two instances of the same job to check ordering
164 | dao.createJobInstance(fooJob, new JobParameters());
165 |
166 | List jobInstances = dao.getJobInstances(fooJob, 1, 2);
167 | assertEquals(1, jobInstances.size());
168 | assertEquals(fooJob, jobInstances.get(0).getJobName());
169 | assertEquals(Integer.valueOf(0), jobInstances.get(0).getVersion());
170 |
171 | }
172 |
173 | /**
174 | * Create and retrieve a job instance.
175 | *
176 | * @throws Exception when shit happens
177 | */
178 | @Transactional
179 | @Test
180 | public void testGetLastInstancesPastEnd() throws Exception {
181 |
182 | testCreateAndRetrieve();
183 |
184 | // unrelated job instance that should be ignored by the query
185 | dao.createJobInstance("anotherJob", new JobParameters());
186 |
187 | // we need two instances of the same job to check ordering
188 | dao.createJobInstance(fooJob, new JobParameters());
189 |
190 | List jobInstances = dao.getJobInstances(fooJob, 4, 2);
191 | assertEquals(0, jobInstances.size());
192 |
193 | }
194 |
195 | /**
196 | * Trying to create instance twice for the same job+parameters causes error
197 | */
198 | @Transactional
199 | @Test(expected = IllegalStateException.class)
200 | public void testCreateDuplicateInstance() {
201 | dao.createJobInstance(fooJob, fooParams);
202 | dao.createJobInstance(fooJob, fooParams);
203 | }
204 |
205 | @Transactional
206 | @Test
207 | public void testCreationAddsVersion() {
208 |
209 | JobInstance jobInstance = new JobInstance((long) 1, new JobParameters(), "testVersionAndId");
210 |
211 | assertNull(jobInstance.getVersion());
212 |
213 | jobInstance = dao.createJobInstance("testVersion", new JobParameters());
214 |
215 | assertNotNull(jobInstance.getVersion());
216 | }
217 |
218 | }
219 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/AbstractStepExecutionDaoTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2007 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.batch.mongo.dao;
18 |
19 | import com.mongodb.DB;
20 | import org.junit.Before;
21 | import org.junit.Test;
22 | import org.springframework.batch.core.*;
23 | import org.springframework.batch.core.repository.JobRepository;
24 | import org.springframework.batch.core.repository.dao.StepExecutionDao;
25 | import org.springframework.batch.mongo.config.Database;
26 | import org.springframework.batch.mongo.step.StepSupport;
27 | import org.springframework.beans.factory.annotation.Autowired;
28 | import org.springframework.dao.OptimisticLockingFailureException;
29 | import org.springframework.transaction.annotation.Transactional;
30 |
31 | import java.util.Collection;
32 | import java.util.Date;
33 |
34 | import static org.junit.Assert.*;
35 |
36 | /**
37 | * Tests for {@link StepExecutionDao} implementations.
38 | *
39 | * @see #getStepExecutionDao()
40 | */
41 | public abstract class AbstractStepExecutionDaoTests {
42 |
43 | protected StepExecutionDao dao;
44 |
45 | protected JobInstance jobInstance;
46 |
47 | protected JobExecution jobExecution;
48 |
49 | protected Step step;
50 |
51 | protected StepExecution stepExecution;
52 |
53 | protected JobRepository repository;
54 |
55 | @Autowired
56 | @Database(Database.Purpose.BATCH)
57 | protected DB db;
58 |
59 | /**
60 | * @return {@link StepExecutionDao} implementation ready for use.
61 | */
62 | protected abstract StepExecutionDao getStepExecutionDao();
63 |
64 | /**
65 | * @return {@link JobRepository} that uses the stepExecution dao.
66 | */
67 | protected abstract JobRepository getJobRepository();
68 |
69 | @Before
70 | public void onSetUp() throws Exception {
71 | db.dropDatabase();
72 | repository = getJobRepository();
73 | jobExecution = repository.createJobExecution("job", new JobParameters());
74 | jobInstance = jobExecution.getJobInstance();
75 | step = new StepSupport("foo");
76 | stepExecution = new StepExecution(step.getName(), jobExecution);
77 | dao = getStepExecutionDao();
78 | }
79 |
80 | @Transactional
81 | @Test
82 | public void testSaveExecutionAssignsIdAndVersion() throws Exception {
83 |
84 | assertNull(stepExecution.getId());
85 | assertNull(stepExecution.getVersion());
86 | dao.saveStepExecution(stepExecution);
87 | assertNotNull(stepExecution.getId());
88 | assertNotNull(stepExecution.getVersion());
89 | }
90 |
91 | @Transactional
92 | @Test
93 | public void testSaveAndGetExecution() {
94 |
95 | stepExecution.setStatus(BatchStatus.STARTED);
96 | stepExecution.setReadSkipCount(7);
97 | stepExecution.setProcessSkipCount(2);
98 | stepExecution.setWriteSkipCount(5);
99 | stepExecution.setProcessSkipCount(11);
100 | stepExecution.setRollbackCount(3);
101 | stepExecution.setLastUpdated(new Date(System.currentTimeMillis()));
102 | stepExecution.setReadCount(17);
103 | stepExecution.setFilterCount(15);
104 | stepExecution.setWriteCount(13);
105 | dao.saveStepExecution(stepExecution);
106 |
107 | StepExecution retrieved = dao.getStepExecution(jobExecution, stepExecution.getId());
108 |
109 | assertStepExecutionsAreEqual(stepExecution, retrieved);
110 | assertNotNull(retrieved.getVersion());
111 | assertNotNull(retrieved.getJobExecution());
112 | assertNotNull(retrieved.getJobExecution().getId());
113 | assertNotNull(retrieved.getJobExecution().getJobId());
114 | assertNotNull(retrieved.getJobExecution().getJobInstance());
115 |
116 | }
117 |
118 | @Transactional
119 | @Test
120 | public void testSaveAndGetNonExistentExecution() {
121 | assertNull(dao.getStepExecution(jobExecution, 45677L));
122 | }
123 |
124 | @Transactional
125 | @Test
126 | public void testSaveAndFindExecution() {
127 |
128 | stepExecution.setStatus(BatchStatus.STARTED);
129 | stepExecution.setReadSkipCount(7);
130 | stepExecution.setWriteSkipCount(5);
131 | stepExecution.setRollbackCount(3);
132 | dao.saveStepExecution(stepExecution);
133 |
134 | dao.addStepExecutions(jobExecution);
135 | Collection retrieved = jobExecution.getStepExecutions();
136 | assertStepExecutionsAreEqual(stepExecution, retrieved.iterator().next());
137 | }
138 |
139 | @Transactional
140 | @Test
141 | public void testGetForNotExistingJobExecution() {
142 | assertNull(dao.getStepExecution(new JobExecution(jobInstance, (long) 777), 11L));
143 | }
144 |
145 | /**
146 | * To-be-saved execution must not already have an id.
147 | */
148 | @Transactional
149 | @Test(expected = IllegalArgumentException.class)
150 | public void testSaveExecutionWithIdAlreadySet() {
151 | stepExecution.setId((long) 7);
152 | dao.saveStepExecution(stepExecution);
153 | }
154 |
155 | /**
156 | * To-be-saved execution must not already have a version.
157 | */
158 | @Transactional
159 | @Test(expected = IllegalArgumentException.class)
160 | public void testSaveExecutionWithVersionAlreadySet() {
161 | stepExecution.incrementVersion();
162 | dao.saveStepExecution(stepExecution);
163 | }
164 |
165 | /**
166 | * Update and retrieve updated StepExecution - make sure the update is
167 | * reflected as expected and version number has been incremented
168 | */
169 | @Transactional
170 | @Test
171 | public void testUpdateExecution() {
172 | stepExecution.setStatus(BatchStatus.STARTED);
173 | dao.saveStepExecution(stepExecution);
174 | Integer versionAfterSave = stepExecution.getVersion();
175 |
176 | stepExecution.setStatus(BatchStatus.ABANDONED);
177 | stepExecution.setLastUpdated(new Date(System.currentTimeMillis()));
178 | dao.updateStepExecution(stepExecution);
179 | assertEquals(versionAfterSave + 1, stepExecution.getVersion().intValue());
180 |
181 | StepExecution retrieved = dao.getStepExecution(jobExecution, stepExecution.getId());
182 | assertEquals(stepExecution, retrieved);
183 | assertEquals(stepExecution.getLastUpdated(), retrieved.getLastUpdated());
184 | assertEquals(BatchStatus.ABANDONED, retrieved.getStatus());
185 | }
186 |
187 | /**
188 | * Exception should be raised when the version of update argument doesn't
189 | * match the version of persisted entity.
190 | */
191 | @Transactional
192 | @Test(expected = OptimisticLockingFailureException.class)
193 | public void testConcurrentModificationException() {
194 | step = new StepSupport("foo");
195 |
196 | StepExecution exec1 = new StepExecution(step.getName(), jobExecution);
197 | dao.saveStepExecution(exec1);
198 |
199 | StepExecution exec2 = new StepExecution(step.getName(), jobExecution);
200 | exec2.setId(exec1.getId());
201 |
202 | exec2.incrementVersion();
203 | assertEquals(new Integer(0), exec1.getVersion());
204 | assertEquals(exec1.getVersion(), exec2.getVersion());
205 |
206 | dao.updateStepExecution(exec1);
207 | assertEquals(new Integer(1), exec1.getVersion());
208 | dao.updateStepExecution(exec2);
209 |
210 | }
211 |
212 | @Test
213 | public void testGetStepExecutionsWhenNoneExist() throws Exception {
214 | int count = jobExecution.getStepExecutions().size();
215 | dao.addStepExecutions(jobExecution);
216 | assertEquals("Incorrect size of collection", count, jobExecution.getStepExecutions().size());
217 | }
218 |
219 | private void assertStepExecutionsAreEqual(StepExecution expected, StepExecution actual) {
220 | assertEquals(expected.getId(), actual.getId());
221 | assertEquals(expected.getStartTime(), actual.getStartTime());
222 | assertEquals(expected.getEndTime(), actual.getEndTime());
223 | assertEquals(expected.getSkipCount(), actual.getSkipCount());
224 | assertEquals(expected.getCommitCount(), actual.getCommitCount());
225 | assertEquals(expected.getReadCount(), actual.getReadCount());
226 | assertEquals(expected.getWriteCount(), actual.getWriteCount());
227 | assertEquals(expected.getFilterCount(), actual.getFilterCount());
228 | assertEquals(expected.getWriteSkipCount(), actual.getWriteSkipCount());
229 | assertEquals(expected.getReadSkipCount(), actual.getReadSkipCount());
230 | assertEquals(expected.getProcessSkipCount(), actual.getProcessSkipCount());
231 | assertEquals(expected.getRollbackCount(), actual.getRollbackCount());
232 | assertEquals(expected.getExitStatus(), actual.getExitStatus());
233 | assertEquals(expected.getLastUpdated(), actual.getLastUpdated());
234 | assertEquals(expected.getExitStatus(), actual.getExitStatus());
235 | assertEquals(expected.getJobExecutionId(), actual.getJobExecutionId());
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/MongoDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.DB;
4 | import junit.framework.Assert;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.springframework.batch.mongo.config.Database;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.test.context.ContextConfiguration;
11 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
12 |
13 |
14 | /**
15 | * Created by IntelliJ IDEA.
16 | *
17 | * @author JBaruch
18 | * @since 20-Apr-2010
19 | */
20 | @ContextConfiguration(locations = {"classpath:application-config.xml"})
21 | @RunWith(SpringJUnit4ClassRunner.class)
22 | public class MongoDaoTests {
23 |
24 | @Autowired
25 | @Database(Database.Purpose.BATCH)
26 | private DB batchDB;
27 |
28 | @Autowired
29 | private MongoJobExecutionDao dao;
30 |
31 | @Before
32 | public void setUp() throws Exception {
33 | batchDB.dropDatabase();
34 | }
35 |
36 | @Test
37 | public void testGetNextId() {
38 | for (long i = 1; i <= 100; i++) {
39 | long id = dao.getNextId(MongoJobExecutionDao.class.getSimpleName());
40 | Assert.assertEquals(i, id);
41 |
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/MongoExecutionContextDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.springframework.batch.core.repository.dao.ExecutionContextDao;
5 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
6 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
7 | import org.springframework.batch.core.repository.dao.StepExecutionDao;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.test.context.ContextConfiguration;
10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
11 |
12 |
13 | /**
14 | * Created by IntelliJ IDEA.
15 | *
16 | * @author Baruch S.
17 | * @since Apr 22, 2010
18 | */
19 |
20 | @RunWith(SpringJUnit4ClassRunner.class)
21 | @ContextConfiguration(locations = {"classpath:application-config.xml"})
22 | public class MongoExecutionContextDaoTests extends AbstractExecutionContextDaoTests {
23 | @Autowired
24 | private JobExecutionDao jobExecutionDao;
25 | @Autowired
26 | private JobInstanceDao jobInstanceDao;
27 | @Autowired
28 | private StepExecutionDao stepExecutionDao;
29 | @Autowired
30 | private ExecutionContextDao executionContextDao;
31 |
32 | @Override
33 | protected JobExecutionDao getJobExecutionDao() {
34 | return jobExecutionDao;
35 | }
36 |
37 | @Override
38 | protected JobInstanceDao getJobInstanceDao() {
39 | return jobInstanceDao;
40 | }
41 |
42 | @Override
43 | protected StepExecutionDao getStepExecutionDao() {
44 | return stepExecutionDao;
45 | }
46 |
47 | @Override
48 | protected ExecutionContextDao getExecutionContextDao() {
49 | return executionContextDao;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/MongoJobDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import com.mongodb.BasicDBObject;
4 | import com.mongodb.DBObject;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.springframework.batch.core.ExitStatus;
8 | import org.springframework.batch.core.JobExecution;
9 | import org.springframework.test.context.ContextConfiguration;
10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
11 | import org.springframework.transaction.annotation.Transactional;
12 |
13 | import static org.junit.Assert.assertEquals;
14 |
15 | @RunWith(SpringJUnit4ClassRunner.class)
16 | @ContextConfiguration(locations = {"classpath:application-config.xml"})
17 | public class MongoJobDaoTests extends AbstractJobDaoTests {
18 |
19 | public static final String LONG_STRING = "A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String A very long String ";
20 |
21 | @Transactional
22 | @Test
23 | public void testUpdateJobExecutionWithLongExitCode() {
24 |
25 | jobExecution.setExitStatus(ExitStatus.COMPLETED
26 | .addExitDescription(LONG_STRING));
27 | jobExecutionDao.updateJobExecution(jobExecution);
28 |
29 |
30 | DBObject dbObject = db.getCollection(JobExecution.class.getSimpleName()).findOne(new BasicDBObject(MongoJobInstanceDao.JOB_INSTANCE_ID_KEY, jobInstance.getId()));
31 | assertEquals(LONG_STRING, dbObject.get(AbstractMongoDao.EXIT_MESSAGE_KEY));
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/MongoJobExecutionDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
5 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.test.context.ContextConfiguration;
8 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
9 |
10 |
11 | /**
12 | * Created by IntelliJ IDEA.
13 | *
14 | * @author Baruch S.
15 | * @since Apr 22, 2010
16 | */
17 | @RunWith(SpringJUnit4ClassRunner.class)
18 | @ContextConfiguration(locations = {"classpath:application-config.xml"})
19 | public class MongoJobExecutionDaoTests extends AbstractJobExecutionDaoTests {
20 |
21 | @Autowired
22 | private JobExecutionDao jobExecutionDao;
23 | @Autowired
24 | private JobInstanceDao jobInstanceDao;
25 |
26 | @Override
27 | protected JobExecutionDao getJobExecutionDao() {
28 | return jobExecutionDao;
29 | }
30 |
31 | @Override
32 | protected JobInstanceDao getJobInstanceDao() {
33 | return jobInstanceDao;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/MongoJobInstanceDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.batch.core.JobExecution;
6 | import org.springframework.batch.core.JobInstance;
7 | import org.springframework.batch.core.JobParameters;
8 | import org.springframework.batch.core.JobParametersBuilder;
9 | import org.springframework.batch.core.repository.dao.JobExecutionDao;
10 | import org.springframework.batch.core.repository.dao.JobInstanceDao;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.test.context.ContextConfiguration;
13 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
14 |
15 | import java.math.BigInteger;
16 | import java.security.MessageDigest;
17 |
18 | import static org.junit.Assert.assertEquals;
19 |
20 | @RunWith(SpringJUnit4ClassRunner.class)
21 | @ContextConfiguration(locations = {"classpath:application-config.xml"})
22 | public class MongoJobInstanceDaoTests extends AbstractJobInstanceDaoTests {
23 |
24 | @Autowired
25 | private JobExecutionDao jobExecutionDao;
26 | @Autowired
27 | private JobInstanceDao jobInstanceDao;
28 |
29 | protected JobInstanceDao getJobInstanceDao() {
30 | return jobInstanceDao;
31 | }
32 |
33 | @Test
34 | public void testFindJobInstanceByExecution() {
35 |
36 | JobInstance jobInstance = dao.createJobInstance("testInstance",
37 | new JobParameters());
38 | JobExecution jobExecution = new JobExecution(jobInstance, 2L);
39 | jobExecutionDao.saveJobExecution(jobExecution);
40 |
41 | JobInstance returnedInstance = dao.getJobInstance(jobExecution);
42 | assertEquals(jobInstance, returnedInstance);
43 | }
44 |
45 | @Test
46 | public void testCreateJobKey() {
47 |
48 | MongoJobInstanceDao jdbcDao = (MongoJobInstanceDao) dao;
49 | JobParameters jobParameters = new JobParametersBuilder().addString(
50 | "foo", "bar").addString("bar", "foo").toJobParameters();
51 | String key = jdbcDao.createJobKey(jobParameters);
52 | assertEquals(32, key.length());
53 |
54 | }
55 |
56 | @Test
57 | public void testCreateJobKeyOrdering() {
58 |
59 | MongoJobInstanceDao jdbcDao = (MongoJobInstanceDao) dao;
60 | JobParameters jobParameters1 = new JobParametersBuilder().addString(
61 | "foo", "bar").addString("bar", "foo").toJobParameters();
62 | String key1 = jdbcDao.createJobKey(jobParameters1);
63 | JobParameters jobParameters2 = new JobParametersBuilder().addString(
64 | "bar", "foo").addString("foo", "bar").toJobParameters();
65 | String key2 = jdbcDao.createJobKey(jobParameters2);
66 | assertEquals(key1, key2);
67 |
68 | }
69 |
70 | @Test
71 | public void testHexing() throws Exception {
72 | MessageDigest digest = MessageDigest.getInstance("MD5");
73 | byte[] bytes = digest.digest("f78spx".getBytes("UTF-8"));
74 | StringBuffer output = new StringBuffer();
75 | for (byte bite : bytes) {
76 | output.append(String.format("%02x", bite));
77 | }
78 | assertEquals("Wrong hash: " + output, 32, output.length());
79 | String value = String.format("%032x", new BigInteger(1, bytes));
80 | assertEquals("Wrong hash: " + value, 32, value.length());
81 | assertEquals(value, output.toString());
82 | }
83 | }
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/dao/MongoStepExecutionDaoTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.dao;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.springframework.batch.core.repository.JobRepository;
5 | import org.springframework.batch.core.repository.dao.StepExecutionDao;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.test.context.ContextConfiguration;
8 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
9 |
10 |
11 | /**
12 | * Created by IntelliJ IDEA.
13 | *
14 | * @author Baruch S.
15 | * @since Apr 22, 2010
16 | */
17 | @RunWith(SpringJUnit4ClassRunner.class)
18 | @ContextConfiguration(locations = {"classpath:application-config.xml"})
19 | public class MongoStepExecutionDaoTests extends AbstractStepExecutionDaoTests {
20 |
21 | @Autowired
22 | private StepExecutionDao stepExecutionDao;
23 |
24 | @Autowired
25 | private JobRepository jobRepository;
26 |
27 | @Override
28 | protected StepExecutionDao getStepExecutionDao() {
29 | return stepExecutionDao;
30 | }
31 |
32 | @Override
33 | protected JobRepository getJobRepository() {
34 | return jobRepository;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/example/ExampleItemReader.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.example;
2 |
3 | import org.springframework.batch.item.ItemReader;
4 | import org.springframework.stereotype.Component;
5 |
6 | /**
7 | * {@link ItemReader} with hard-coded input data.
8 | */
9 | @Component
10 | public class ExampleItemReader implements ItemReader {
11 |
12 | private String[] input = {"Hello world!", null};
13 |
14 | private int index = 0;
15 |
16 | /**
17 | * Reads next record from input
18 | */
19 | public String read() throws Exception {
20 | if (index < input.length) {
21 | return input[index++];
22 | } else {
23 | return null;
24 | }
25 |
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/example/ExampleItemReaderTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.example;
2 |
3 | import org.junit.Test;
4 |
5 | import static junit.framework.Assert.assertEquals;
6 |
7 | public class ExampleItemReaderTests {
8 |
9 | private ExampleItemReader reader = new ExampleItemReader();
10 |
11 | @Test
12 | public void testReadOnce() throws Exception {
13 | assertEquals("Hello world!", reader.read());
14 | }
15 |
16 | @Test
17 | public void testReadTwice() throws Exception {
18 | reader.read();
19 | assertEquals(null, reader.read());
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/batch/mongo/example/ExampleItemWriter.java:
--------------------------------------------------------------------------------
1 | package org.springframework.batch.mongo.example;
2 |
3 | import org.apache.commons.logging.Log;
4 | import org.apache.commons.logging.LogFactory;
5 | import org.springframework.batch.item.ItemWriter;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.List;
9 |
10 |
11 | /**
12 | * Dummy {@link ItemWriter} which only logs data it receives.
13 | */
14 | @Component
15 | public class ExampleItemWriter implements ItemWriter