Skip to content

Commit

Permalink
Merge pull request #1636 from marklogic/release/6.5
Browse files Browse the repository at this point in the history
Merge release/6.5 into master
  • Loading branch information
rjrudin authored Jan 29, 2024
2 parents 0e0ab40 + e01c236 commit b68bab9
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 142 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group=com.marklogic
version=6.4.1
version=6.5.0
describedName=MarkLogic Java Client API
publishUrl=file:../marklogic-java/releases

Expand Down
15 changes: 7 additions & 8 deletions marklogic-client-api-functionaltests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,16 @@ dependencies {
implementation 'org.skyscreamer:jsonassert:1.5.1'
implementation 'org.slf4j:slf4j-api:1.7.36'
implementation 'commons-io:commons-io:2.11.0'
implementation 'com.squareup.okio:okio:3.4.0'
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.2'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.3'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.3'
implementation "org.jdom:jdom2:2.0.6.1"
implementation "com.marklogic:ml-app-deployer:4.5.2"
implementation "com.marklogic:ml-app-deployer:4.6.1"

testImplementation 'ch.qos.logback:logback-classic:1.3.5'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testImplementation 'ch.qos.logback:logback-classic:1.3.14'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
testImplementation 'org.xmlunit:xmlunit-legacy:2.9.0'
testImplementation 'org.apache.commons:commons-lang3:3.12.0'
testImplementation 'org.apache.commons:commons-lang3:3.14.0'
testImplementation 'org.apache.httpcomponents:httpclient:4.5.14'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,71 +423,4 @@ public void testPointInTimeQueryNonDeterministicSet() {
// Doc count should be zero after both batchers are done.
assertEquals(0, dbClient.newServerEval().xquery(query1).eval().next().getNumber().intValue());
}

/*
* Trigger batch failure by calling incorrect meta data values
*/

@Test
public void testOnBatchFailure() {
String jsonDoc = "{" +
"\"employees\": [" +
"{ \"firstName\":\"Will\" , \"lastName\":\"Kirkham\" }," +
"{ \"firstName\":\"Hus\" , \"lastName\":\"Wattan\" }," +
"{ \"firstName\":\"Rod\" , \"lastName\":\"Mendez\" }]" +
"}";

// Use WriteBatcher to write the files.
WriteBatcher wbatcher = dmManager.newWriteBatcher();

wbatcher.withBatchSize(1000);
StringHandle handle = new StringHandle();
handle.set(jsonDoc);
String uri = null;

// Insert 100 documents
for (int i = 0; i < 100; i++) {
uri = "lastname" + i + ".json";
wbatcher.add(uri, handle);
}
wbatcher.flushAndWait();

List<String> docExporterList = Collections.synchronizedList(new ArrayList<String>());

QueryManager queryMgr = dbClient.newQueryManager();
StringQueryDefinition querydef = queryMgr.newStringDefinition();
querydef.setCriteria("Will AND Hus");
StringBuilder onBatchFailureStr = new StringBuilder();

QueryBatcher exportBatcher = dmManager.newQueryBatcher(querydef)
.withBatchSize(50)
.onUrisReady(
new ExportListener()
.withMetadataCategory(DocumentManager.Metadata.METADATAVALUES)
.onDocumentReady(doc -> {
String uriOfDoc = doc.getUri();
docExporterList.add(uriOfDoc);
}
)
.onFailure((batch, throwable) -> {
onBatchFailureStr.append("From onBatchFailure QA Exception");
System.out.println("From onBatchFailure " + throwable.getMessage());
System.out.println("From onBatchFailure QA Exception");
}
)
)
.onUrisReady(batch -> {
System.out.println("Batch Numer is " + batch.getJobBatchNumber());
})
.onQueryFailure(exception -> {
System.out.println("Exceptions thrown from testOnBatchFailure callback onQueryFailure");
exception.printStackTrace();
});
dmManager.startJob(exportBatcher);

exportBatcher.awaitCompletion();

assertTrue(onBatchFailureStr.toString().contains("From onBatchFailure QA Exception"),
"Unexpected exception: " + onBatchFailureStr);
}
}
29 changes: 13 additions & 16 deletions marklogic-client-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,49 +16,46 @@ dependencies {
implementation 'org.glassfish.jaxb:jaxb-core:2.3.0.1'
}

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

implementation 'com.sun.mail:javax.mail:1.6.2'
implementation 'javax.ws.rs:javax.ws.rs-api:2.1.1'
implementation 'org.slf4j:slf4j-api:1.7.36'
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.2'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.15.2'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.15.2'
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.3'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.15.3'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.3'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.15.3'

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

testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
// Forcing junit version to avoid vulnerability with older version in xmlunit
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.xmlunit:xmlunit-legacy:2.9.1'
testImplementation project(':examples')

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

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

testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.2'
testImplementation 'ch.qos.logback:logback-classic:1.3.5'
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.3'
testImplementation 'ch.qos.logback:logback-classic:1.3.14'
// schema validation issue with testImplementation 'xerces:xercesImpl:2.12.0'
testImplementation 'org.opengis.cite.xerces:xercesImpl-xsd11:2.12-beta-r1667115'
testImplementation 'org.apache.commons:commons-lang3:3.12.0'
testImplementation 'org.apache.commons:commons-lang3:3.14.0'
testImplementation 'org.apache.httpcomponents:httpclient:4.5.14'
testImplementation 'com.opencsv:opencsv:4.6'
testImplementation 'org.geonames:geonames:1.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,49 @@ public DatabaseClientBuilder withKeyStoreAlgorithm(String algorithm) {
props.put(PREFIX + "ssl.keystore.algorithm", algorithm);
return this;
}

/**
* Supports constructing an {@code X509TrustManager} based on the given file path, which should point to a Java
* key store or trust store.
*
* @param path
* @return
* @since 6.5.0
*/
public DatabaseClientBuilder withTrustStorePath(String path) {
props.put(PREFIX + "ssl.truststore.path", path);
return this;
}

/**
* @param password optional password for a trust store
* @return
* @since 6.5.0
*/
public DatabaseClientBuilder withTrustStorePassword(String password) {
props.put(PREFIX + "ssl.truststore.password", password);
return this;
}

/**
* @param type e.g. "JKS"
* @return
* @since 6.5.0
*/
public DatabaseClientBuilder withTrustStoreType(String type) {
props.put(PREFIX + "ssl.truststore.type", type);
return this;
}

/**
* @param algorithm e.g. "SunX509"
* @return
* @since 6.5.0
*/
public DatabaseClientBuilder withTrustStoreAlgorithm(String algorithm) {
props.put(PREFIX + "ssl.truststore.algorithm", algorithm);
return this;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,10 @@ public String getCertificatePassword() {
* <li>marklogic.client.ssl.keystore.password = must be a String; optional password for a key store; since 6.4.0.</li>
* <li>marklogic.client.ssl.keystore.type = must be a String; optional type for a key store, defaults to "JKS"; since 6.4.0.</li>
* <li>marklogic.client.ssl.keystore.algorithm = must be a String; optional algorithm for a key store, defaults to "SunX509"; since 6.4.0.</li>
* <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>
* <li>marklogic.client.ssl.truststore.password = must be a String; optional password for a trust store; since 6.5.0.</li>
* <li>marklogic.client.ssl.truststore.type = must be a String; optional type for a trust store, defaults to "JKS"; since 6.5.0.</li>
* <li>marklogic.client.ssl.truststore.algorithm = must be a String; optional algorithm for a trust store, defaults to "SunX509"; since 6.5.0.</li>
* </ol>
*
* @param propertySource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;
Expand Down Expand Up @@ -317,9 +318,29 @@ private X509TrustManager getTrustManager() {
throw new IllegalArgumentException("Trust manager must be an instanceof " + X509TrustManager.class.getName());
}
}

String path = getNullableStringValue("ssl.truststore.path");
if (path != null && path.trim().length() > 0) {
return buildTrustManagerFromTrustStorePath(path);
}

return null;
}

/**
* Added in 6.5.0 to support configuring a trust manager via properties.
*
* @param path
* @return
*/
private X509TrustManager buildTrustManagerFromTrustStorePath(String path) {
final String password = getNullableStringValue("ssl.truststore.password");
final String type = getNullableStringValue("ssl.truststore.type", "JKS");
final String algorithm = getNullableStringValue("ssl.truststore.algorithm", "SunX509");
KeyStore trustStore = SSLUtil.getKeyStore(path, password != null ? password.toCharArray() : null, type);
return (X509TrustManager) SSLUtil.getTrustManagers(algorithm, trustStore)[0];
}

private SSLContext getSSLContext() {
Object val = propertySource.apply(PREFIX + "sslContext");
if (val != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,7 @@ public void execute(Plan plan) {
@Override
public void execute(Plan plan, Transaction transaction) {
PlanBuilderBaseImpl.RequestPlan requestPlan = checkPlan(plan);
RequestParameters params = newRowsParamsBuilder(requestPlan)
.withOutput("execute")
.getRequestParameters();
RequestParameters params = newRowsParamsBuilder(requestPlan).getRequestParameters();
RESTServiceResultIterator iter = submitPlan(requestPlan, params, transaction);
if (iter != null) {
iter.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static TrustManager[] getDefaultTrustManagers() {
* @param trustManagerAlgorithm e.g. "SunX509".
* @param optionalKeyStore if not null, used to initialize the TrustManagerFactory constructed based on the
* given algorithm.
* @return
* @return an array of at least length 1 where the first instance is an {@code X509TrustManager}
*/
public static TrustManager[] getTrustManagers(String trustManagerAlgorithm, KeyStore optionalKeyStore) {
TrustManagerFactory trustManagerFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void invalidQuery() {
RowManager rowManager = client.newRowManager();
PlanBuilder op = rowManager.newPlanBuilder();
PlanBuilder.ModifyPlan plan = op
.fromView("opticUnitTest", "musician")
.fromView("opticUnitTest", "musician_ml10")
.where(op.eq(op.col("dob"), op.xs.string("this is not a valid date")));

List<JsonNode> returnedRows = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@

import java.io.BufferedReader;
import java.io.StringReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -203,6 +200,24 @@ public void testJsonRowsForest2Threads() throws Exception {
public void testJsonDocs1Thread() throws Exception {
runDocsTest(jsonBatcher(1));
}

@Test
void noRowsReturned() {
RowBatcher<JsonNode> rowBatcher = jsonBatcher(1);
RowManager rowMgr = rowBatcher.getRowManager();
RawQueryDSLPlan plan = rowMgr.newRawQueryDSLPlan(
new StringHandle("op.fromView('rowBatcherUnitTest', 'code').where(op.eq(op.col('field1'), 12345))"));

List<JsonNode> results = new ArrayList<>();
rowBatcher.withBatchView(plan).onSuccess(batch -> results.add(batch.getRowsDoc()));
moveMgr.startJob(rowBatcher);
rowBatcher.awaitCompletion();
moveMgr.stopJob(rowBatcher);

assertEquals(0, results.size(), "Expecting no results as the Optic query shouldn't match any rows; " +
"also expecting no error to occur.");
}

@Test
public void testJsonDocs3Threads() throws Exception {
runDocsTest(jsonBatcher(3));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,24 +481,30 @@ private void testViewRows(RowSet<RowRecord> rows) {
assertEquals( 2, rowNum);
}

@Test
public void testSQL() {
RowManager rowMgr = Common.client.newRowManager();
PlanBuilder p = rowMgr.newPlanBuilder();
PlanBuilder.ExportablePlan builtPlan =
p.fromSql("select * from opticUnitTest.musician_ml10");
int rowNum = 0;
String exception = "";
try {
for (RowRecord row: rowMgr.resultRows(builtPlan)) {
rowNum++;
}
} catch (Exception e) {
exception = e.toString();
}
assertEquals(4, rowNum);
assertEquals("", exception);
}
@Test
void testSQL() {
final String query = "select * from opticUnitTest.musician_ml10";
RowManager mgr = Common.client.newRowManager();

RowSet<RowRecord> rows = mgr.resultRows(mgr.newPlanBuilder().fromSql(query));
assertEquals(4, rows.stream().count());

JsonNode doc = mgr.resultDoc(mgr.newPlanBuilder().fromSql(query), new JacksonHandle()).get();
assertEquals(3, doc.get("columns").size());
assertEquals(4, doc.get("rows").size());
}

@Test
void sqlNoRows() {
final String query = "select * from opticUnitTest.musician_ml10 where lastName = 'NOT_FOUND'";
RowManager mgr = Common.client.newRowManager();

RowSet<RowRecord> rows = mgr.resultRows(mgr.newPlanBuilder().fromSql(query));
assertEquals(0, rows.stream().count());

JsonNode doc = mgr.resultDoc(mgr.newPlanBuilder().fromSql(query), new JacksonHandle()).get();
assertNull(doc);
}

@Test
public void testSQL0Result() {
Expand Down
Loading

0 comments on commit b68bab9

Please sign in to comment.