Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit 7762b9d

Browse files
committed
#85 Improvements to job properties
1 parent 38aa709 commit 7762b9d

27 files changed

+574
-100
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
group=com.marklogic
22
javadocsDir=../gh-pages-marklogic-java/javadocs
3-
version=3.2.0
3+
version=3.3.0-dev

src/main/java/com/marklogic/client/ext/datamovement/BatcherConfig.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
*/
1010
public class BatcherConfig extends LoggingObject {
1111

12+
public final static Integer DEFAULT_BATCH_SIZE = 100;
13+
public final static Integer DEFAULT_THREAD_COUNT = 8;
14+
1215
private String jobName;
13-
private Integer batchSize = 100;
14-
private Integer threadCount = 8;
16+
private Integer batchSize = DEFAULT_BATCH_SIZE;
17+
private Integer threadCount = DEFAULT_THREAD_COUNT;
1518
private ForestConfiguration forestConfig;
1619

1720
public void prepareBatcher(Batcher batcher) {

src/main/java/com/marklogic/client/ext/datamovement/QueryBatcherBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,10 @@
99
*/
1010
public interface QueryBatcherBuilder {
1111

12+
/**
13+
* @param databaseClient typically needed for constructing a QueryDefinition
14+
* @param dataMovementManager
15+
* @return
16+
*/
1217
QueryBatcher buildQueryBatcher(DatabaseClient databaseClient, DataMovementManager dataMovementManager);
1318
}

src/main/java/com/marklogic/client/ext/datamovement/job/AbstractQueryBatcherJob.java

Lines changed: 115 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,25 @@
33
import com.marklogic.client.DatabaseClient;
44
import com.marklogic.client.datamovement.*;
55
import com.marklogic.client.ext.datamovement.*;
6+
import com.marklogic.client.ext.datamovement.listener.SimpleBatchLoggingListener;
67

78
import java.util.ArrayList;
89
import java.util.Arrays;
910
import java.util.List;
11+
import java.util.Properties;
12+
import java.util.function.Consumer;
1013

1114
/**
1215
* Provides basic plumbing for implementing QueryBatcherJob.
1316
*/
14-
public abstract class AbstractQueryBatcherJob extends BatcherConfig implements QueryBatcherJob {
17+
public abstract class AbstractQueryBatcherJob extends BatcherConfig implements QueryBatcherJob, ConfigurableJob {
18+
19+
private List<JobProperty> jobProperties = new ArrayList<>();
1520

1621
private List<QueryBatchListener> urisReadyListeners;
1722
private List<QueryFailureListener> queryFailureListeners;
1823

19-
private boolean applyConsistentSnapshot = false;
24+
private boolean consistentSnapshot = false;
2025
private boolean awaitCompletion = true;
2126
private boolean stopJobAfterCompletion = true;
2227

@@ -30,12 +35,17 @@ public abstract class AbstractQueryBatcherJob extends BatcherConfig implements Q
3035
private String[] whereCollections;
3136
private String whereUriPattern;
3237
private String whereUrisQuery;
38+
private boolean requireWhereProperty = true;
3339

3440
/**
3541
* @return a description of the job that is useful for logging purposes.
3642
*/
3743
protected abstract String getJobDescription();
3844

45+
protected AbstractQueryBatcherJob() {
46+
addQueryBatcherJobProperties();
47+
}
48+
3949
@Override
4050
public QueryBatcherJobTicket run(DatabaseClient databaseClient) {
4151
DataMovementManager dmm = this.dataMovementManager != null ? this.dataMovementManager : databaseClient.newDataMovementManager();
@@ -65,6 +75,77 @@ public QueryBatcherJobTicket run(DatabaseClient databaseClient) {
6575
return new QueryBatcherJobTicket(dmm, queryBatcher, jobTicket);
6676
}
6777

78+
@Override
79+
public List<String> configureJob(Properties props) {
80+
List<String> messages = new ArrayList<>();
81+
82+
for (JobProperty jobProperty : this.jobProperties) {
83+
String name = jobProperty.getPropertyName();
84+
String value = props.getProperty(name);
85+
if (value != null && value.trim().length() > 0) {
86+
jobProperty.getPropertyValueConsumer().accept(value);
87+
} else if (jobProperty.isRequired()) {
88+
messages.add("The property '" + name + "' is required");
89+
}
90+
}
91+
92+
if (requireWhereProperty && !isWherePropertySet() && queryBatcherBuilder == null) {
93+
messages.add("At least one 'where' property must be set for selecting records to process");
94+
}
95+
96+
return messages;
97+
}
98+
99+
@Override
100+
public List<JobProperty> getJobProperties() {
101+
return jobProperties;
102+
}
103+
104+
protected void addQueryBatcherJobProperties() {
105+
addJobProperty("batchSize", "Number of records to process at once; defaults to " + DEFAULT_BATCH_SIZE,
106+
value -> setBatchSize(Integer.parseInt(value)));
107+
108+
addJobProperty("consistentSnapshot", "Whether or not to apply a consistent snapshot to the query for records; defaults to false",
109+
value -> setConsistentSnapshot(Boolean.parseBoolean(value)));
110+
111+
addJobProperty("jobName", "Optional name for the Data Movement job", value -> setJobName(value));
112+
113+
addJobProperty("logBatches", "Log each batch to stdout as it's processed",
114+
value -> addUrisReadyListener(new SimpleBatchLoggingListener()));
115+
116+
addJobProperty("logBatchesWithLogger", "Log each batch as it's processed at the info-level using SLF4J",
117+
value -> addUrisReadyListener(new SimpleBatchLoggingListener(true)));
118+
119+
addJobProperty("threadCount", "Number of threads to process records with; default to " + DEFAULT_THREAD_COUNT,
120+
value -> setThreadCount(Integer.parseInt(value)));
121+
122+
addWhereJobProperties();
123+
}
124+
125+
protected void addWhereJobProperties() {
126+
addJobProperty("whereCollections", "Comma-delimited list of collections for selecting records to process",
127+
value -> setWhereCollections(value.split(",")));
128+
129+
addJobProperty("whereUriPattern", "URI pattern for selecting records to process",
130+
value -> setWhereUriPattern(value));
131+
132+
addJobProperty("whereUris", "Comma-delimited list of URIs for selecting records to process",
133+
value -> setWhereUris(value.split(",")));
134+
135+
addJobProperty("whereUrisQuery", "CTS URIs query for selecting records to process",
136+
value -> setWhereUrisQuery(value));
137+
}
138+
139+
protected void addJobProperty(String name, String description, Consumer<String> propertyValueConsumer) {
140+
jobProperties.add(new SimpleJobProperty(name, description, propertyValueConsumer));
141+
}
142+
143+
protected void addRequiredJobProperty(String name, String description, Consumer<String> propertyValueConsumer) {
144+
SimpleJobProperty prop = new SimpleJobProperty(name, description, propertyValueConsumer);
145+
prop.setRequired(true);
146+
jobProperties.add(prop);
147+
}
148+
68149
/**
69150
* Can be overridden by the subclass to prepare the QueryBatcher before the job is started.
70151
*
@@ -73,7 +154,7 @@ public QueryBatcherJobTicket run(DatabaseClient databaseClient) {
73154
protected void prepareQueryBatcher(QueryBatcher queryBatcher) {
74155
super.prepareBatcher(queryBatcher);
75156

76-
if (applyConsistentSnapshot) {
157+
if (consistentSnapshot) {
77158
queryBatcher.withConsistentSnapshot();
78159
}
79160

@@ -91,30 +172,26 @@ protected void prepareQueryBatcher(QueryBatcher queryBatcher) {
91172
}
92173

93174
/**
94-
* For subclasses to use to construct a QueryBatcherBuilder based on the "where" properties that have been set.
95-
*
96175
* @return
97176
*/
98177
protected QueryBatcherBuilder newQueryBatcherBuilder() {
99178
if (queryBatcherBuilder != null) {
100179
return queryBatcherBuilder;
101180
}
102181

103-
if (isWherePropertySet()) {
104-
if (whereUris != null && whereUris.length > 0) {
105-
return new DocumentUrisQueryBatcherBuilder(whereUris);
106-
}
107-
if (whereCollections != null) {
108-
return new CollectionsQueryBatcherBuilder(whereCollections);
109-
}
110-
if (whereUriPattern != null) {
111-
return new UriPatternQueryBatcherBuilder(whereUriPattern);
112-
}
113-
if (whereUrisQuery != null) {
114-
return new UrisQueryQueryBatcherBuilder(whereUrisQuery);
115-
}
182+
if (whereUris != null && whereUris.length > 0) {
183+
return new DocumentUrisQueryBatcherBuilder(whereUris);
184+
}
185+
if (whereCollections != null) {
186+
return new CollectionsQueryBatcherBuilder(whereCollections);
187+
}
188+
if (whereUriPattern != null) {
189+
return new UriPatternQueryBatcherBuilder(whereUriPattern);
190+
}
191+
if (whereUrisQuery != null) {
192+
return new UrisQueryQueryBatcherBuilder(whereUrisQuery);
116193
}
117-
throw new IllegalArgumentException("No 'where' property has been set, unable to construct a QueryBatcherBuilder");
194+
return null;
118195
}
119196

120197
/**
@@ -126,20 +203,20 @@ protected String getQueryDescription() {
126203
return "with custom query";
127204
}
128205

129-
if (isWherePropertySet()) {
130-
if (whereUris != null && whereUris.length > 0) {
131-
return "with URIs " + Arrays.asList(whereUris);
132-
} else if (whereCollections != null && whereCollections.length > 0) {
133-
return "in collections " + Arrays.asList(this.whereCollections);
134-
} else if (whereUriPattern != null) {
135-
return "matching URI pattern [" + whereUriPattern + "]";
136-
} else if (whereUrisQuery != null) {
137-
return "matching URIs query [" + whereUrisQuery + "]";
138-
}
206+
if (whereUris != null && whereUris.length > 0) {
207+
return "with URIs " + Arrays.asList(whereUris);
208+
} else if (whereCollections != null && whereCollections.length > 0) {
209+
return "in collections " + Arrays.asList(this.whereCollections);
210+
} else if (whereUriPattern != null) {
211+
return "matching URI pattern [" + whereUriPattern + "]";
212+
} else if (whereUrisQuery != null) {
213+
return "matching URIs query [" + whereUrisQuery + "]";
139214
}
140-
throw new IllegalArgumentException("No 'where' property has been set, unable to construct a description of the query");
215+
216+
return null;
141217
}
142218

219+
143220
protected boolean isWherePropertySet() {
144221
return
145222
(whereUris != null && whereUris.length > 0)
@@ -217,12 +294,12 @@ public AbstractQueryBatcherJob setQueryFailureListeners(List<QueryFailureListene
217294
return this;
218295
}
219296

220-
public boolean isApplyConsistentSnapshot() {
221-
return applyConsistentSnapshot;
297+
public boolean isConsistentSnapshot() {
298+
return consistentSnapshot;
222299
}
223300

224-
public AbstractQueryBatcherJob setApplyConsistentSnapshot(boolean applyConsistentSnapshot) {
225-
this.applyConsistentSnapshot = applyConsistentSnapshot;
301+
public AbstractQueryBatcherJob setConsistentSnapshot(boolean consistentSnapshot) {
302+
this.consistentSnapshot = consistentSnapshot;
226303
return this;
227304
}
228305

@@ -253,4 +330,8 @@ public AbstractQueryBatcherJob setQueryBatcherBuilder(QueryBatcherBuilder queryB
253330
this.queryBatcherBuilder = queryBatcherBuilder;
254331
return this;
255332
}
333+
334+
public void setRequireWhereProperty(boolean requireWhereProperty) {
335+
this.requireWhereProperty = requireWhereProperty;
336+
}
256337
}

src/main/java/com/marklogic/client/ext/datamovement/job/AddCollectionsJob.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,24 @@ public class AddCollectionsJob extends AbstractQueryBatcherJob implements QueryB
88

99
private String[] collections;
1010

11+
public AddCollectionsJob() {
12+
super();
13+
addRequiredJobProperty("collections", "Comma-delimited list collections to which selected records are added",
14+
value -> setCollections(value.split(",")));
15+
}
16+
1117
public AddCollectionsJob(String... collections) {
12-
this.collections = collections;
13-
this.addUrisReadyListener(new AddCollectionsListener(collections));
18+
this();
19+
setCollections(collections);
1420
}
1521

1622
@Override
1723
protected String getJobDescription() {
1824
return "Adding documents " + getQueryDescription() + " to collections " + Arrays.asList(collections);
1925
}
2026

27+
public void setCollections(String... collections) {
28+
this.collections = collections;
29+
this.addUrisReadyListener(new AddCollectionsListener(collections));
30+
}
2131
}

src/main/java/com/marklogic/client/ext/datamovement/job/AddPermissionsJob.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,26 @@ public class AddPermissionsJob extends AbstractQueryBatcherJob {
88

99
private String[] rolesAndCapabilities;
1010

11+
public AddPermissionsJob() {
12+
super();
13+
14+
addRequiredJobProperty("permissions",
15+
"Comma-delimited list of roles and capabilities defining permissions added to selected records",
16+
value -> setRolesAndCapabilities(value.split(",")));
17+
}
18+
1119
public AddPermissionsJob(String... rolesAndCapabilities) {
12-
this.rolesAndCapabilities = rolesAndCapabilities;
13-
this.addUrisReadyListener(new AddPermissionsListener(rolesAndCapabilities));
20+
this();
21+
setRolesAndCapabilities(rolesAndCapabilities);
1422
}
1523

1624
@Override
1725
protected String getJobDescription() {
1826
return "Adding permissions " + Arrays.asList(rolesAndCapabilities) + " to documents " + getQueryDescription();
1927
}
2028

29+
public void setRolesAndCapabilities(String... rolesAndCapabilities) {
30+
this.rolesAndCapabilities = rolesAndCapabilities;
31+
this.addUrisReadyListener(new AddPermissionsListener(rolesAndCapabilities));
32+
}
2133
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.marklogic.client.ext.datamovement.job;
2+
3+
import java.util.List;
4+
import java.util.Properties;
5+
6+
/**
7+
* Interface for a job to implement when it can be configured via a Properties object. A primary benefit for clients is
8+
* that they can call the getJobProperties method and e.g. print out this list so a user knows what properties are
9+
* available for a job.
10+
*/
11+
public interface ConfigurableJob {
12+
13+
/**
14+
* Configure this job with the given set of Properties.
15+
*
16+
* @return a list of strings, with each presumably being a validation error message
17+
*/
18+
List<String> configureJob(Properties props);
19+
20+
/**
21+
* @return the list of JobProperty objects for this job. One use case for this is for a client to print out the
22+
* name and description of each property.
23+
*/
24+
List<JobProperty> getJobProperties();
25+
}

src/main/java/com/marklogic/client/ext/datamovement/job/DeleteCollectionsJob.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@ public class DeleteCollectionsJob extends AbstractQueryBatcherJob {
1010

1111
private String[] collections;
1212

13+
public DeleteCollectionsJob() {
14+
super();
15+
addRequiredJobProperty("collections", "Comma-delimited list of collections to delete",
16+
value -> setCollections(value.split(",")));
17+
}
18+
1319
public DeleteCollectionsJob(String... collections) {
14-
this.collections = collections;
15-
this.addUrisReadyListener(new DeleteListener());
20+
this();
21+
setCollections(collections);
1622
}
1723

1824
@Override
@@ -24,4 +30,14 @@ protected QueryBatcherBuilder newQueryBatcherBuilder() {
2430
protected String getJobDescription() {
2531
return "Deleting collections: " + Arrays.asList(collections);
2632
}
33+
34+
public void setCollections(String... collections) {
35+
this.collections = collections;
36+
this.addUrisReadyListener(new DeleteListener());
37+
}
38+
39+
@Override
40+
protected void addWhereJobProperties() {
41+
// These don't apply to this job
42+
}
2743
}

0 commit comments

Comments
 (0)