Skip to content
This repository was archived by the owner on Feb 27, 2023. It is now read-only.

Commit 94c8c3c

Browse files
author
Scott Stafford
committed
Merge branch 'dev'
2 parents 590b698 + bf1e0f1 commit 94c8c3c

File tree

143 files changed

+1336
-674
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+1336
-674
lines changed

README.md

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ Have you ever written a long running batch processing job, like migrating data f
1616

1717
# What are the main features of MarkLogic Spring Batch?
1818
* Provide custom ItemReaders, ItemProcessors, ItemWriters, and tasklets for writing custom MarkLogic batch processing jobs.
19+
* Mitigate the risk of the Spring Batch learning curve by providing examples of creating your own custom batch processing job
1920
* Persist the metadata of any JobExecution with a MarkLogic [JobRepository](http://docs.spring.io/spring-batch/trunk/reference/html/domain.html#domainJobRepository)
2021
* Execute one of many generic MarkLogic batch processing jobs for importing, transforming, and exporting data in a MarkLogic database
21-
* Mitigate the risk of the Spring Batch learning curve by providing examples of creating your own custom batch processing job
2222

2323
# How do I build a custom MarkLogic batch processing job?
2424

25-
The [examples directory](https://github.com/sastafford/marklogic-spring-batch/tree/master/examples) provides examples of MarkLogic batch processing jobs. Each example is setup to be deployed as a command line utility. The [base job](https://github.com/sastafford/marklogic-spring-batch/tree/master/examples/base) provides a template for creating a custom import batch processing job.
25+
The [examples directory](https://github.com/sastafford/marklogic-spring-batch/tree/master/examples) provides different examples of MarkLogic batch processing jobs. Each example is setup to be deployed as a command line utility. The [base job example](https://github.com/sastafford/marklogic-spring-batch/tree/master/examples/base) is a bare bones Spring configuration template for creating a custom ingest batch processing job.
2626

2727
## Import the MSB jars
2828
Create a build.gradle file to import the MarkLogic Spring Batch (MSB) jars. Use the [latest version](https://github.com/sastafford/marklogic-spring-batch/releases) of the MSB jars.
@@ -38,8 +38,8 @@ repositories {
3838
}
3939
4040
dependencies {
41-
compile "com.marklogic:marklogic-spring-batch-core:0.5.0"
42-
testComplile "com.marklogic:marklogic-spring-batch-test:0.5.0"
41+
compile "com.marklogic:marklogic-spring-batch-core:0.6.0"
42+
testComplile "com.marklogic:marklogic-spring-batch-test:0.6.0"
4343
}
4444
```
4545

@@ -52,10 +52,10 @@ Create a test class by subclassing the [AbstractJobTest](https://github.com/sast
5252
# How do I execute my job?
5353
An easy way to execute your job is to execute it as a command line utility similar to MarkLogic Content Pump or CORB. An easy way to deploy the job is via the [Gradle Application Plugin](https://docs.gradle.org/current/userguide/application_plugin.html). Once you have your JobConfiguration created and have verified that it works, then execute the following gradle command to build an executable.
5454

55-
gradle distZip
56-
57-
This will create a zip file under ../install/distributions that can be transferred and executed on any host.
55+
gradle installDist
5856

57+
This command will create two start scripts, one for Windows and one for Unix, and will package up all the libraries. The installation package can be found under the ./build/install/<artifactId>. directory where artifactId is a variable of the same name defined in your build.gradle or gradle.properties file. Once this exists, you can then execute the start script and pass the required and any optional parameters defined by your job. See either the [importInvoices task from the rdbms_2 build.gradle file](https://github.com/sastafford/marklogic-spring-batch/blob/master/examples/rdbms_2/build.gradle) or the manually created [runInovices.bat](https://github.com/sastafford/marklogic-spring-batch/blob/master/examples/rdbms_2/runInvoices.bat) file. The runInvoices.bat assumes that the gradle installDist task has already been executed.
58+
5959
Each MarkLogic Spring Batch execution application (based on the Main class) expects a few command line parameters. Custom parameters can be defined in the JobConfiguration.
6060

6161
* config - The class name of your Job configuration
@@ -69,9 +69,15 @@ Each MarkLogic Spring Batch execution application (based on the Main class) expe
6969
* jrPassword (optional) - the Job Repository MarkLogic password
7070

7171
```
72-
./jobExec --config com.marklogic.spring.batch.job.JobNameConfig.class --host localhost --port 8010 --username admin --password admin --customParam1 xyz --customParamX abc
72+
./<artifactId_script_name> --config com.marklogic.spring.batch.job.JobNameConfig --host localhost --port 8010 --username admin --password admin --customParam1 xyz --customParamX abc
7373
```
7474

75+
# How do I distribute my command line job utility?
76+
77+
The following gradle command will create a zip file under ./build/distributions that can be transferred and executed on any host.
78+
79+
gradle distZip
80+
7581
## Create a Gradle JavaExec task
7682

7783
The second option is to create a gradle JavaExec task that would execute your job via a gradle command. Here is an example gradle task taken from the [mysql-sakila example](https://github.com/sastafford/marklogic-spring-batch/blob/master/examples/mysql-sakila/build.gradle).
@@ -105,19 +111,19 @@ gradle migrateActors
105111
If you want to use a MarkLogic Job Repository then you first need to install a new application onto your MarkLogic database. A MarkLogic Job Repository can be installed via the executable created with your Gradle application plugin.
106112

107113
```
108-
./jobs deployMarkLogicJobRepository --jr_host localhost --jr_port 8011 --jr_username admin --jr_password admin
114+
./<jobArtifactScriptName> deployMarkLogicJobRepository --jr_host localhost --jr_port 8011 --jr_username admin --jr_password admin
109115
```
110116

111117
If you ever need to undeploy the JobRepository then you can issue the following command.
112118

113119
```
114-
./jobs undeployMarkLogicJobRepository --jr_host localhost --jr_port 8011 --jr_username admin --jr_password admin
120+
./<jobArtifactScriptName> undeployMarkLogicJobRepository --jr_host localhost --jr_port 8011 --jr_username admin --jr_password admin
115121
```
116122

117123
Now when you execute your job, then add the additional parameters for the MarkLogic Job Repository. All JobExecution metadata is now logged to the MarkLogic JobRepository.
118124

119125
```
120-
./jobs --config com.marklogic.spring.batch.job.JobNameConfig.class --host localhost --port 8010 --username admin --password admin --custom_param1 xyz --customParamX abc --jr_host localhost --jr_port 8011 --jr_username admin --jr_password admin
126+
./<jobArtifactScriptName> --config com.marklogic.spring.batch.job.JobNameConfig --host localhost --port 8010 --username admin --password admin --custom_param1 xyz --customParamX abc --jr_host localhost --jr_port 8011 --jr_username admin --jr_password admin
121127
```
122128

123129
# How can I contribute to the project?

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ subprojects {
3535
}
3636
}
3737

38-
configure(subprojects.findAll {it.name != 'jobs'}) {
38+
configure(subprojects.findAll {it.name != 'examples'}) {
3939
apply plugin: "maven-publish"
4040

4141
task sourcesJar(type: Jar, dependsOn: classes) {
@@ -107,4 +107,4 @@ task testExamples(type: GradleBuild) {
107107
tasks = [ 'test' ]
108108
}
109109

110-
task testAll(dependsOn:[':core:test', 'jobs:test', 'testExamples'] )
110+
task testAll(dependsOn:[':core:test', 'examples:test', 'testExamples'] )

core/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
plugins {
2-
id "com.marklogic.ml-gradle" version "2.2.0"
2+
id "com.marklogic.ml-gradle" version "2.3.3"
33
id "com.jfrog.bintray" version "1.6"
44
}
55

core/src/main/java/com/marklogic/spring/batch/config/ConfigTypeFilter.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.marklogic.client.spring.BasicConfig;
44
import com.marklogic.spring.batch.MainConfig;
5-
import com.marklogic.spring.batch.core.repository.dao.MarkLogicDaoConfig;
65
import org.springframework.core.type.ClassMetadata;
76
import org.springframework.core.type.filter.AbstractClassTestingTypeFilter;
87

@@ -17,7 +16,6 @@ protected boolean match(ClassMetadata metadata) {
1716
String name = metadata.getClassName();
1817
return name.startsWith("org.springframework")
1918
|| name.equals(MainConfig.class.getName())
20-
|| name.equals(MarkLogicDaoConfig.class.getName())
2119
|| name.equals(BasicConfig.class.getName());
2220
}
2321

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.marklogic.spring.batch.config;
2+
3+
import com.marklogic.client.DatabaseClient;
4+
import com.marklogic.client.helper.DatabaseClientProvider;
5+
import com.marklogic.spring.batch.core.explore.support.MarkLogicJobExplorerFactoryBean;
6+
import com.marklogic.spring.batch.core.repository.support.MarkLogicJobRepositoryFactoryBean;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
10+
import org.springframework.batch.core.explore.JobExplorer;
11+
import org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean;
12+
import org.springframework.batch.core.launch.JobLauncher;
13+
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
14+
import org.springframework.batch.core.repository.JobRepository;
15+
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
16+
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
17+
import org.springframework.beans.factory.annotation.Autowired;
18+
import org.springframework.stereotype.Component;
19+
import org.springframework.transaction.PlatformTransactionManager;
20+
21+
import javax.annotation.PostConstruct;
22+
23+
@Component
24+
public class MarkLogicBatchConfigurer implements BatchConfigurer {
25+
26+
private final static Logger logger = LoggerFactory.getLogger(MarkLogicBatchConfigurer.class);
27+
private DatabaseClient databaseClient;
28+
private JobRepository jobRepository;
29+
private JobExplorer jobExplorer;
30+
private JobLauncher jobLauncher;
31+
private PlatformTransactionManager transactionManager;
32+
33+
protected MarkLogicBatchConfigurer() {}
34+
35+
@Autowired
36+
public MarkLogicBatchConfigurer(DatabaseClientProvider databaseClientProvider) {
37+
this.databaseClient = databaseClientProvider.getDatabaseClient();
38+
}
39+
40+
@PostConstruct
41+
public void initialize() throws Exception {
42+
if(databaseClient == null) {
43+
logger.warn("No DatabaseClient was provided...using a Map based JobRepository");
44+
45+
if(this.transactionManager == null) {
46+
this.transactionManager = new ResourcelessTransactionManager();
47+
}
48+
49+
MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean(this.transactionManager);
50+
jobRepositoryFactory.afterPropertiesSet();
51+
this.jobRepository = jobRepositoryFactory.getObject();
52+
53+
MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(jobRepositoryFactory);
54+
jobExplorerFactory.afterPropertiesSet();
55+
this.jobExplorer = jobExplorerFactory.getObject();
56+
} else {
57+
this.transactionManager = new ResourcelessTransactionManager();
58+
this.jobRepository = createJobRepository();
59+
this.jobExplorer = createJobExplorer();
60+
}
61+
this.jobLauncher = createJobLauncher();
62+
}
63+
64+
protected JobRepository createJobRepository() throws Exception {
65+
MarkLogicJobRepositoryFactoryBean factory = new MarkLogicJobRepositoryFactoryBean();
66+
factory.setDatabaseClient(databaseClient);
67+
factory.setTransactionManager(transactionManager);
68+
factory.afterPropertiesSet();
69+
return factory.getObject();
70+
}
71+
72+
protected JobExplorer createJobExplorer() throws Exception {
73+
MarkLogicJobExplorerFactoryBean factory = new MarkLogicJobExplorerFactoryBean();
74+
factory.setDatabaseClient(databaseClient);
75+
factory.afterPropertiesSet();
76+
return factory.getObject();
77+
}
78+
79+
protected JobLauncher createJobLauncher() throws Exception {
80+
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
81+
jobLauncher.setJobRepository(jobRepository);
82+
jobLauncher.afterPropertiesSet();
83+
return jobLauncher;
84+
}
85+
86+
@Override
87+
public JobRepository getJobRepository() throws Exception {
88+
return jobRepository;
89+
}
90+
91+
@Override
92+
public PlatformTransactionManager getTransactionManager() throws Exception {
93+
return transactionManager;
94+
}
95+
96+
@Override
97+
public JobLauncher getJobLauncher() throws Exception {
98+
return jobLauncher;
99+
}
100+
101+
@Override
102+
public JobExplorer getJobExplorer() throws Exception {
103+
return jobExplorer;
104+
}
105+
106+
}

core/src/main/java/com/marklogic/spring/batch/config/support/JobRepositoryConfigurer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void initialize() {
6161

6262
JobInstanceDao jobInstanceDao = new MarkLogicJobInstanceDao(client);
6363
JobExecutionDao jobExecutionDao = new MarkLogicJobExecutionDao(client);
64-
MarkLogicStepExecutionDao stepExecutionDao = new MarkLogicStepExecutionDao(client);
64+
MarkLogicStepExecutionDao stepExecutionDao = new MarkLogicStepExecutionDao(client, jobExecutionDao);
6565
stepExecutionDao.setJobExecutionDao(jobExecutionDao);
6666
ExecutionContextDao executionContextDao = new MarkLogicExecutionContextDao(jobExecutionDao, stepExecutionDao);
6767

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.marklogic.spring.batch.core.explore.support;
2+
3+
import com.marklogic.client.DatabaseClient;
4+
import com.marklogic.spring.batch.core.repository.dao.MarkLogicExecutionContextDao;
5+
import com.marklogic.spring.batch.core.repository.dao.MarkLogicJobExecutionDao;
6+
import com.marklogic.spring.batch.core.repository.dao.MarkLogicJobInstanceDao;
7+
import com.marklogic.spring.batch.core.repository.dao.MarkLogicStepExecutionDao;
8+
import org.springframework.batch.core.explore.JobExplorer;
9+
import org.springframework.batch.core.explore.support.AbstractJobExplorerFactoryBean;
10+
import org.springframework.batch.core.explore.support.SimpleJobExplorer;
11+
import org.springframework.batch.core.repository.dao.ExecutionContextDao;
12+
import org.springframework.batch.core.repository.dao.JobExecutionDao;
13+
import org.springframework.batch.core.repository.dao.JobInstanceDao;
14+
import org.springframework.batch.core.repository.dao.StepExecutionDao;
15+
import org.springframework.beans.factory.InitializingBean;
16+
import org.springframework.util.Assert;
17+
18+
public class MarkLogicJobExplorerFactoryBean extends AbstractJobExplorerFactoryBean implements InitializingBean {
19+
20+
private DatabaseClient databaseClient;
21+
private JobInstanceDao jobInstanceDao;
22+
private JobExecutionDao jobExecutionDao;
23+
private StepExecutionDao stepExecutionDao;
24+
private ExecutionContextDao executionContextDao;
25+
26+
/**
27+
* Public setter for the {@link DatabaseClient}.
28+
* @param databaseClient a {@link DatabaseClient}
29+
*/
30+
public void setDatabaseClient(DatabaseClient databaseClient) {
31+
this.databaseClient = databaseClient;
32+
}
33+
34+
@Override
35+
protected JobInstanceDao createJobInstanceDao() throws Exception {
36+
return jobInstanceDao;
37+
}
38+
39+
@Override
40+
protected JobExecutionDao createJobExecutionDao() throws Exception {
41+
return jobExecutionDao;
42+
}
43+
44+
@Override
45+
protected StepExecutionDao createStepExecutionDao() throws Exception {
46+
return stepExecutionDao;
47+
}
48+
49+
@Override
50+
protected ExecutionContextDao createExecutionContextDao() throws Exception {
51+
return executionContextDao;
52+
}
53+
54+
@Override
55+
public JobExplorer getObject() throws Exception {
56+
return new SimpleJobExplorer(createJobInstanceDao(),
57+
createJobExecutionDao(), createStepExecutionDao(),
58+
createExecutionContextDao());
59+
}
60+
61+
@Override
62+
public void afterPropertiesSet() throws Exception {
63+
Assert.notNull(databaseClient, "DatabaseClient must not be null.");
64+
jobInstanceDao = new MarkLogicJobInstanceDao(databaseClient);
65+
jobExecutionDao = new MarkLogicJobExecutionDao(databaseClient);
66+
stepExecutionDao = new MarkLogicStepExecutionDao(databaseClient, jobExecutionDao);
67+
executionContextDao = new MarkLogicExecutionContextDao(jobExecutionDao, stepExecutionDao);
68+
}
69+
}

core/src/main/java/com/marklogic/spring/batch/core/repository/MarkLogicSimpleJobRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
import org.springframework.batch.core.repository.dao.JobInstanceDao;
1212
import org.springframework.batch.core.repository.dao.StepExecutionDao;
1313
import org.springframework.batch.core.repository.support.SimpleJobRepository;
14+
import org.springframework.stereotype.Component;
1415
import org.springframework.util.Assert;
1516

17+
@Component
1618
public class MarkLogicSimpleJobRepository extends SimpleJobRepository {
1719

1820
private StepExecutionDao stepExecutionDao;

core/src/main/java/com/marklogic/spring/batch/core/repository/dao/AbstractMarkLogicBatchMetadataDao.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
package com.marklogic.spring.batch.core.repository.dao;
22

33
import com.marklogic.client.helper.LoggingObject;
4-
import org.springframework.beans.factory.annotation.Autowired;
5-
import org.springframework.context.ApplicationContext;
64
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
75

86
import com.marklogic.client.DatabaseClient;
97

108
public abstract class AbstractMarkLogicBatchMetadataDao extends LoggingObject {
119

12-
@Autowired
13-
protected ApplicationContext ctx;
14-
1510
protected DatabaseClient databaseClient;
1611

1712
protected DataFieldMaxValueIncrementer incrementer;
@@ -22,24 +17,13 @@ public abstract class AbstractMarkLogicBatchMetadataDao extends LoggingObject {
2217
public final String SEARCH_OPTIONS_NAME = "spring-batch";
2318

2419
public final String SPRING_BATCH_DIR = "/projects.spring.io/spring-batch/";
25-
public final String SPRING_BATCH_INSTANCE_DIR = SPRING_BATCH_DIR + "instance/";
2620

27-
public final String COLLECTION_JOB_EXECUTION = "http://marklogic.com/spring-batch/job-execution";
2821
public final String COLLECTION_JOB_INSTANCE = "http://marklogic.com/spring-batch/job-instance";
29-
public final String COLLECTION_STEP_EXECUTION = "http://marklogic.com/spring-batch/step-execution";
3022

3123
public DatabaseClient getDatabaseClient() {
3224
return databaseClient;
3325
}
34-
35-
public void setDatabaseClient(DatabaseClient databaseClient) {
36-
this.databaseClient = databaseClient;
37-
}
3826

39-
public DataFieldMaxValueIncrementer getIncrementer() {
40-
return incrementer;
41-
}
42-
4327
public void setIncrementer(DataFieldMaxValueIncrementer incrementer) {
4428
this.incrementer = incrementer;
4529
}

0 commit comments

Comments
 (0)