Skip to content

Commit b68bab9

Browse files
authored
Merge pull request #1636 from marklogic/release/6.5
Merge release/6.5 into master
2 parents 0e0ab40 + e01c236 commit b68bab9

File tree

15 files changed

+196
-142
lines changed

15 files changed

+196
-142
lines changed

Diff for: gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group=com.marklogic
2-
version=6.4.1
2+
version=6.5.0
33
describedName=MarkLogic Java Client API
44
publishUrl=file:../marklogic-java/releases
55

Diff for: marklogic-client-api-functionaltests/build.gradle

+7-8
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,16 @@ dependencies {
2323
implementation 'org.skyscreamer:jsonassert:1.5.1'
2424
implementation 'org.slf4j:slf4j-api:1.7.36'
2525
implementation 'commons-io:commons-io:2.11.0'
26-
implementation 'com.squareup.okio:okio:3.4.0'
27-
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
28-
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.2'
29-
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
26+
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
27+
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.3'
28+
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.3'
3029
implementation "org.jdom:jdom2:2.0.6.1"
31-
implementation "com.marklogic:ml-app-deployer:4.5.2"
30+
implementation "com.marklogic:ml-app-deployer:4.6.1"
3231

33-
testImplementation 'ch.qos.logback:logback-classic:1.3.5'
34-
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
32+
testImplementation 'ch.qos.logback:logback-classic:1.3.14'
33+
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
3534
testImplementation 'org.xmlunit:xmlunit-legacy:2.9.0'
36-
testImplementation 'org.apache.commons:commons-lang3:3.12.0'
35+
testImplementation 'org.apache.commons:commons-lang3:3.14.0'
3736
testImplementation 'org.apache.httpcomponents:httpclient:4.5.14'
3837
}
3938

Diff for: marklogic-client-api-functionaltests/src/test/java/com/marklogic/client/fastfunctest/datamovement/ExportListenerTest.java

-67
Original file line numberDiff line numberDiff line change
@@ -423,71 +423,4 @@ public void testPointInTimeQueryNonDeterministicSet() {
423423
// Doc count should be zero after both batchers are done.
424424
assertEquals(0, dbClient.newServerEval().xquery(query1).eval().next().getNumber().intValue());
425425
}
426-
427-
/*
428-
* Trigger batch failure by calling incorrect meta data values
429-
*/
430-
431-
@Test
432-
public void testOnBatchFailure() {
433-
String jsonDoc = "{" +
434-
"\"employees\": [" +
435-
"{ \"firstName\":\"Will\" , \"lastName\":\"Kirkham\" }," +
436-
"{ \"firstName\":\"Hus\" , \"lastName\":\"Wattan\" }," +
437-
"{ \"firstName\":\"Rod\" , \"lastName\":\"Mendez\" }]" +
438-
"}";
439-
440-
// Use WriteBatcher to write the files.
441-
WriteBatcher wbatcher = dmManager.newWriteBatcher();
442-
443-
wbatcher.withBatchSize(1000);
444-
StringHandle handle = new StringHandle();
445-
handle.set(jsonDoc);
446-
String uri = null;
447-
448-
// Insert 100 documents
449-
for (int i = 0; i < 100; i++) {
450-
uri = "lastname" + i + ".json";
451-
wbatcher.add(uri, handle);
452-
}
453-
wbatcher.flushAndWait();
454-
455-
List<String> docExporterList = Collections.synchronizedList(new ArrayList<String>());
456-
457-
QueryManager queryMgr = dbClient.newQueryManager();
458-
StringQueryDefinition querydef = queryMgr.newStringDefinition();
459-
querydef.setCriteria("Will AND Hus");
460-
StringBuilder onBatchFailureStr = new StringBuilder();
461-
462-
QueryBatcher exportBatcher = dmManager.newQueryBatcher(querydef)
463-
.withBatchSize(50)
464-
.onUrisReady(
465-
new ExportListener()
466-
.withMetadataCategory(DocumentManager.Metadata.METADATAVALUES)
467-
.onDocumentReady(doc -> {
468-
String uriOfDoc = doc.getUri();
469-
docExporterList.add(uriOfDoc);
470-
}
471-
)
472-
.onFailure((batch, throwable) -> {
473-
onBatchFailureStr.append("From onBatchFailure QA Exception");
474-
System.out.println("From onBatchFailure " + throwable.getMessage());
475-
System.out.println("From onBatchFailure QA Exception");
476-
}
477-
)
478-
)
479-
.onUrisReady(batch -> {
480-
System.out.println("Batch Numer is " + batch.getJobBatchNumber());
481-
})
482-
.onQueryFailure(exception -> {
483-
System.out.println("Exceptions thrown from testOnBatchFailure callback onQueryFailure");
484-
exception.printStackTrace();
485-
});
486-
dmManager.startJob(exportBatcher);
487-
488-
exportBatcher.awaitCompletion();
489-
490-
assertTrue(onBatchFailureStr.toString().contains("From onBatchFailure QA Exception"),
491-
"Unexpected exception: " + onBatchFailureStr);
492-
}
493426
}

Diff for: marklogic-client-api/build.gradle

+13-16
Original file line numberDiff line numberDiff line change
@@ -16,49 +16,46 @@ dependencies {
1616
implementation 'org.glassfish.jaxb:jaxb-core:2.3.0.1'
1717
}
1818

19-
// Forcing usage of 3.4.0 instead of 3.2.0 to address vulnerability - https://security.snyk.io/vuln/SNYK-JAVA-COMSQUAREUPOKIO-5820002
20-
implementation 'com.squareup.okio:okio:3.4.0'
21-
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
22-
implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'
19+
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
20+
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
2321
implementation 'io.github.rburgst:okhttp-digest:2.7'
2422

2523
implementation 'com.sun.mail:javax.mail:1.6.2'
2624
implementation 'javax.ws.rs:javax.ws.rs-api:2.1.1'
2725
implementation 'org.slf4j:slf4j-api:1.7.36'
28-
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.2'
29-
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.15.2'
30-
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
31-
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.15.2'
26+
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.3'
27+
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.15.3'
28+
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.3'
29+
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.15.3'
3230

3331
// Only used by extras (which some examples then depend on)
3432
// Forcing codec version to avoid vulnerability with older version in httpclient
35-
compileOnly 'commons-codec:commons-codec:1.15'
33+
compileOnly 'commons-codec:commons-codec:1.16.0'
3634
compileOnly 'org.apache.httpcomponents:httpclient:4.5.14'
3735
compileOnly 'org.jdom:jdom2:2.0.6.1'
3836
compileOnly 'org.dom4j:dom4j:2.1.4'
3937
compileOnly 'com.google.code.gson:gson:2.10.1'
4038

41-
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
39+
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
4240
// Forcing junit version to avoid vulnerability with older version in xmlunit
4341
testImplementation 'junit:junit:4.13.2'
4442
testImplementation 'org.xmlunit:xmlunit-legacy:2.9.1'
4543
testImplementation project(':examples')
4644

4745
// Allows talking to the Manage API. It depends on the Java Client itself, which will usually be a slightly older
4846
// version, but that should not have any impact on the tests.
49-
testImplementation "com.marklogic:ml-app-deployer:4.5.2"
47+
testImplementation "com.marklogic:ml-app-deployer:4.6.1"
5048

5149
// Starting with mockito 5.x, Java 11 is required, so sticking with 4.x as we have to support Java 8.
5250
testImplementation "org.mockito:mockito-core:4.11.0"
5351
testImplementation "org.mockito:mockito-inline:4.11.0"
54-
testImplementation 'com.squareup.okio:okio:3.4.0'
55-
testImplementation "com.squareup.okhttp3:mockwebserver:4.11.0"
52+
testImplementation "com.squareup.okhttp3:mockwebserver:4.12.0"
5653

57-
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.2'
58-
testImplementation 'ch.qos.logback:logback-classic:1.3.5'
54+
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.3'
55+
testImplementation 'ch.qos.logback:logback-classic:1.3.14'
5956
// schema validation issue with testImplementation 'xerces:xercesImpl:2.12.0'
6057
testImplementation 'org.opengis.cite.xerces:xercesImpl-xsd11:2.12-beta-r1667115'
61-
testImplementation 'org.apache.commons:commons-lang3:3.12.0'
58+
testImplementation 'org.apache.commons:commons-lang3:3.14.0'
6259
testImplementation 'org.apache.httpcomponents:httpclient:4.5.14'
6360
testImplementation 'com.opencsv:opencsv:4.6'
6461
testImplementation 'org.geonames:geonames:1.0'

Diff for: marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientBuilder.java

+43
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,49 @@ public DatabaseClientBuilder withKeyStoreAlgorithm(String algorithm) {
301301
props.put(PREFIX + "ssl.keystore.algorithm", algorithm);
302302
return this;
303303
}
304+
305+
/**
306+
* Supports constructing an {@code X509TrustManager} based on the given file path, which should point to a Java
307+
* key store or trust store.
308+
*
309+
* @param path
310+
* @return
311+
* @since 6.5.0
312+
*/
313+
public DatabaseClientBuilder withTrustStorePath(String path) {
314+
props.put(PREFIX + "ssl.truststore.path", path);
315+
return this;
316+
}
317+
318+
/**
319+
* @param password optional password for a trust store
320+
* @return
321+
* @since 6.5.0
322+
*/
323+
public DatabaseClientBuilder withTrustStorePassword(String password) {
324+
props.put(PREFIX + "ssl.truststore.password", password);
325+
return this;
326+
}
327+
328+
/**
329+
* @param type e.g. "JKS"
330+
* @return
331+
* @since 6.5.0
332+
*/
333+
public DatabaseClientBuilder withTrustStoreType(String type) {
334+
props.put(PREFIX + "ssl.truststore.type", type);
335+
return this;
336+
}
337+
338+
/**
339+
* @param algorithm e.g. "SunX509"
340+
* @return
341+
* @since 6.5.0
342+
*/
343+
public DatabaseClientBuilder withTrustStoreAlgorithm(String algorithm) {
344+
props.put(PREFIX + "ssl.truststore.algorithm", algorithm);
345+
return this;
346+
}
304347
}
305348

306349

Diff for: marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientFactory.java

+4
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,10 @@ public String getCertificatePassword() {
13031303
* <li>marklogic.client.ssl.keystore.password = must be a String; optional password for a key store; since 6.4.0.</li>
13041304
* <li>marklogic.client.ssl.keystore.type = must be a String; optional type for a key store, defaults to "JKS"; since 6.4.0.</li>
13051305
* <li>marklogic.client.ssl.keystore.algorithm = must be a String; optional algorithm for a key store, defaults to "SunX509"; since 6.4.0.</li>
1306+
* <li>marklogic.client.ssl.truststore.path = must be a String; specifies a file path for a trust store for SSL and/or certificate authentication; since 6.5.0.</li>
1307+
* <li>marklogic.client.ssl.truststore.password = must be a String; optional password for a trust store; since 6.5.0.</li>
1308+
* <li>marklogic.client.ssl.truststore.type = must be a String; optional type for a trust store, defaults to "JKS"; since 6.5.0.</li>
1309+
* <li>marklogic.client.ssl.truststore.algorithm = must be a String; optional algorithm for a trust store, defaults to "SunX509"; since 6.5.0.</li>
13061310
* </ol>
13071311
*
13081312
* @param propertySource

Diff for: marklogic-client-api/src/main/java/com/marklogic/client/impl/DatabaseClientPropertySource.java

+21
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import javax.net.ssl.SSLContext;
2424
import javax.net.ssl.X509TrustManager;
2525
import java.security.KeyManagementException;
26+
import java.security.KeyStore;
2627
import java.security.NoSuchAlgorithmException;
2728
import java.util.LinkedHashMap;
2829
import java.util.Map;
@@ -317,9 +318,29 @@ private X509TrustManager getTrustManager() {
317318
throw new IllegalArgumentException("Trust manager must be an instanceof " + X509TrustManager.class.getName());
318319
}
319320
}
321+
322+
String path = getNullableStringValue("ssl.truststore.path");
323+
if (path != null && path.trim().length() > 0) {
324+
return buildTrustManagerFromTrustStorePath(path);
325+
}
326+
320327
return null;
321328
}
322329

330+
/**
331+
* Added in 6.5.0 to support configuring a trust manager via properties.
332+
*
333+
* @param path
334+
* @return
335+
*/
336+
private X509TrustManager buildTrustManagerFromTrustStorePath(String path) {
337+
final String password = getNullableStringValue("ssl.truststore.password");
338+
final String type = getNullableStringValue("ssl.truststore.type", "JKS");
339+
final String algorithm = getNullableStringValue("ssl.truststore.algorithm", "SunX509");
340+
KeyStore trustStore = SSLUtil.getKeyStore(path, password != null ? password.toCharArray() : null, type);
341+
return (X509TrustManager) SSLUtil.getTrustManagers(algorithm, trustStore)[0];
342+
}
343+
323344
private SSLContext getSSLContext() {
324345
Object val = propertySource.apply(PREFIX + "sslContext");
325346
if (val != null) {

Diff for: marklogic-client-api/src/main/java/com/marklogic/client/impl/RowManagerImpl.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,7 @@ public void execute(Plan plan) {
215215
@Override
216216
public void execute(Plan plan, Transaction transaction) {
217217
PlanBuilderBaseImpl.RequestPlan requestPlan = checkPlan(plan);
218-
RequestParameters params = newRowsParamsBuilder(requestPlan)
219-
.withOutput("execute")
220-
.getRequestParameters();
218+
RequestParameters params = newRowsParamsBuilder(requestPlan).getRequestParameters();
221219
RESTServiceResultIterator iter = submitPlan(requestPlan, params, transaction);
222220
if (iter != null) {
223221
iter.close();

Diff for: marklogic-client-api/src/main/java/com/marklogic/client/impl/SSLUtil.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static TrustManager[] getDefaultTrustManagers() {
6060
* @param trustManagerAlgorithm e.g. "SunX509".
6161
* @param optionalKeyStore if not null, used to initialize the TrustManagerFactory constructed based on the
6262
* given algorithm.
63-
* @return
63+
* @return an array of at least length 1 where the first instance is an {@code X509TrustManager}
6464
*/
6565
public static TrustManager[] getTrustManagers(String trustManagerAlgorithm, KeyStore optionalKeyStore) {
6666
TrustManagerFactory trustManagerFactory;

Diff for: marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/RowBatcherFailureTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void invalidQuery() {
2727
RowManager rowManager = client.newRowManager();
2828
PlanBuilder op = rowManager.newPlanBuilder();
2929
PlanBuilder.ModifyPlan plan = op
30-
.fromView("opticUnitTest", "musician")
30+
.fromView("opticUnitTest", "musician_ml10")
3131
.where(op.eq(op.col("dob"), op.xs.string("this is not a valid date")));
3232

3333
List<JsonNode> returnedRows = new ArrayList<>();

Diff for: marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/RowBatcherTest.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,7 @@
4343

4444
import java.io.BufferedReader;
4545
import java.io.StringReader;
46-
import java.util.Arrays;
47-
import java.util.Collections;
48-
import java.util.HashSet;
49-
import java.util.Set;
46+
import java.util.*;
5047
import java.util.concurrent.ConcurrentSkipListSet;
5148
import java.util.concurrent.atomic.AtomicBoolean;
5249
import java.util.concurrent.atomic.AtomicInteger;
@@ -203,6 +200,24 @@ public void testJsonRowsForest2Threads() throws Exception {
203200
public void testJsonDocs1Thread() throws Exception {
204201
runDocsTest(jsonBatcher(1));
205202
}
203+
204+
@Test
205+
void noRowsReturned() {
206+
RowBatcher<JsonNode> rowBatcher = jsonBatcher(1);
207+
RowManager rowMgr = rowBatcher.getRowManager();
208+
RawQueryDSLPlan plan = rowMgr.newRawQueryDSLPlan(
209+
new StringHandle("op.fromView('rowBatcherUnitTest', 'code').where(op.eq(op.col('field1'), 12345))"));
210+
211+
List<JsonNode> results = new ArrayList<>();
212+
rowBatcher.withBatchView(plan).onSuccess(batch -> results.add(batch.getRowsDoc()));
213+
moveMgr.startJob(rowBatcher);
214+
rowBatcher.awaitCompletion();
215+
moveMgr.stopJob(rowBatcher);
216+
217+
assertEquals(0, results.size(), "Expecting no results as the Optic query shouldn't match any rows; " +
218+
"also expecting no error to occur.");
219+
}
220+
206221
@Test
207222
public void testJsonDocs3Threads() throws Exception {
208223
runDocsTest(jsonBatcher(3));

Diff for: marklogic-client-api/src/test/java/com/marklogic/client/test/rows/RowManagerTest.java

+24-18
Original file line numberDiff line numberDiff line change
@@ -481,24 +481,30 @@ private void testViewRows(RowSet<RowRecord> rows) {
481481
assertEquals( 2, rowNum);
482482
}
483483

484-
@Test
485-
public void testSQL() {
486-
RowManager rowMgr = Common.client.newRowManager();
487-
PlanBuilder p = rowMgr.newPlanBuilder();
488-
PlanBuilder.ExportablePlan builtPlan =
489-
p.fromSql("select * from opticUnitTest.musician_ml10");
490-
int rowNum = 0;
491-
String exception = "";
492-
try {
493-
for (RowRecord row: rowMgr.resultRows(builtPlan)) {
494-
rowNum++;
495-
}
496-
} catch (Exception e) {
497-
exception = e.toString();
498-
}
499-
assertEquals(4, rowNum);
500-
assertEquals("", exception);
501-
}
484+
@Test
485+
void testSQL() {
486+
final String query = "select * from opticUnitTest.musician_ml10";
487+
RowManager mgr = Common.client.newRowManager();
488+
489+
RowSet<RowRecord> rows = mgr.resultRows(mgr.newPlanBuilder().fromSql(query));
490+
assertEquals(4, rows.stream().count());
491+
492+
JsonNode doc = mgr.resultDoc(mgr.newPlanBuilder().fromSql(query), new JacksonHandle()).get();
493+
assertEquals(3, doc.get("columns").size());
494+
assertEquals(4, doc.get("rows").size());
495+
}
496+
497+
@Test
498+
void sqlNoRows() {
499+
final String query = "select * from opticUnitTest.musician_ml10 where lastName = 'NOT_FOUND'";
500+
RowManager mgr = Common.client.newRowManager();
501+
502+
RowSet<RowRecord> rows = mgr.resultRows(mgr.newPlanBuilder().fromSql(query));
503+
assertEquals(0, rows.stream().count());
504+
505+
JsonNode doc = mgr.resultDoc(mgr.newPlanBuilder().fromSql(query), new JacksonHandle()).get();
506+
assertNull(doc);
507+
}
502508

503509
@Test
504510
public void testSQL0Result() {

0 commit comments

Comments
 (0)